Python编程从入门到实践_第九章_类

第九章:类(Class)


  • 面向过程的编程思想将一个功能分解为一 个一个小的步骤,我们通过完成一个一 个的小的步骤来完成一个程序。(C)

    • 优点:这种编程方式 ,符合我们人类的思维,编写起来相对比较简单
    • 缺点:但是这种方式编写代码的往往只适用于一个功能;如果要在实现别的功能,即使功能相差极小,也往往要重新编写代码,所以它可复用性比较低,并且难于维护
  • 面向对象是按人们认识客观世界的系统思维方式,采用基于对象(实体)的概念建立模型,模拟客观世界分析、设计、实现软件的编程思想,通过面向对象的理念使计算机软件系统能与现实世界中的系统一一对应。(C++,Java,Python)

    • 优点:这种方式编写的代码,比较容易阅读,并且比较易于维护,容易复用。
    • 缺点:但是这种方式编写,不太符合常规的思维,编写起来稍微麻烦一点(面向过程是面向对象的基础)
  • 面向对象编程是最有效的软件编写方法之一。此编程方式的落地需要使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” 的使用。

类就是一个模板,模板里可以包含多个函数,函数里实现一些功能

对象则是根据模板创建的实例,通过实例对象可以执行类中的函数

  • Python 是一种面向对象的编程语言。在Python中创建一个类和对象是很容易的。Python 中的几乎所有东西都是对象,拥有属性和方法。

  • 如果你以前没有接触过面向对象的编程语言,那你可能需要先了解一些面向对象语言的一些基本特征,在头脑里头形成一个基本的面向对象的概念,这样有助于你更容易的学习Python的面向对象编程。接下来我们先来简单的了解下面向对象的一些基本特征。

    1. 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。

    2. 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。

    3. 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。

    4. 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。

    5. 实例变量:定义在方法中的变量,只作用于当前实例的类。

    6. 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,素以Dog也是一个Animal。

    7. 实例化:创建一个类的实例,类的具体对象。
      方法:类中定义的函数。

    8. 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

9.1 创建和使用类

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。

9.1.1 创建Dog类

任务: 编写一个表示小狗的简单类

  • 该类表示不是特定的小狗,而是任何小狗
  • 大多数小狗具备两项信息(名字,年龄),两项行为(蹲下,打滚),使用Dog类包含这些通用的信息和行为
  • 使用Dog类创建表示特定小狗的实例
class Dog(): #首字母大写表示类
    "模拟小狗"
# 类中的函数称为方法,方法名称前后各有_,避免与普通方法发生命名冲突 
# 方法__init__()包含三个形参,其中self必不可少,且必须在其他形参前,self会自动传递,根据Dog类创建实例时,只需给形参name 和age提供值
    def __init__(self, name, age): 
        "初始化属性name和age"    
        self.name = name  #以self为前缀的变量可供类中的所有方法使用,可以通过类的任何实例来访问
        self.age = age    #可通过实例访问的变量称为属性
        
    def sit(self): # 方法
        "模拟小狗收到命令后蹲下"
        print(f"{self.name} is now sitting.")
        
    def roll_over(self):
        "模拟小狗收到命令后打滚"
        print(f"{self.name} rolled over.")
  • 根据约定,在Python中,首字母大写的名称指的是类,这个类定义中的括号是空的,因为我们要从空白创建这个类。
  • 方法 init:
  • 类中的函数称为方法;init()方法是一个特殊方法,每当我们根据Dog类创建实例时,python都会自动运行它。两个下划线
  • 在上面例子中我们将方法_init_定义成包含三个形参:self,name,age。在这个方法的定义中,形参self必不可少,而且要位于其他形参之前,这是因为python调用这个_init_()方法创建实例时,将自动传入实参self。每个与类相关联的方法调用都自动传递实参self,它是一个指向实例本身的引用,让实例能访问类中属性和方法。
  • 我们创建Dog实例时,python将调用Dog类的方法_init_()。我们将通过实参向Dog()传递名字和年龄;self会自动传递,因此我们不需要传递它。
  • Dog类还定义了另外两个方法:sit()和roll_over()。由于这些方法不需要额外的信息,如名字和年龄,因此它们只有一个形参self。

9.1.2 根据类创建实例

  • 可将类看做如何创建实例的说明

任务: 创建一个表示特定小狗的实例

my_dog = Dog('Willie',6) # 小写名称表示根据类创建的实例

print(f"My dog's name is {my_dog.name}.")
print(f"My dog is {my_dog.age} years old.")  
My dog's name is Willie.
My dog is 6 years old.
# 访问属性
my_dog.name
'Willie'
# 调用方法
my_dog.sit()
Willie is now sitting.
# 创建多个实例
my_dog = Dog('Willie',6)
your_dog = Dog('Lucy',3)

print(f"My dog's name is {my_dog.name}.")
print(f"My dog is {my_dog.age} years old.")
my_dog.sit()

print(f"\nYour dog's name is {my_dog.name}.")
print(f"Your dog is {my_dog.age} years old.")
your_dog.roll_over()
My dog's name is Willie.
My dog is 6 years old.
Willie is now sitting.

Your dog's name is Willie.
Your dog is 6 years old.
Lucy rolled over.

9.2 使用类和实例

  • 可使用类来描述现实世界的很多情景
  • 如何根据类来创建实例

9.2.1 Car类

class Car:
    "模拟汽车"
    
    def __init__(self, make, model,year):
        "初始化,描述汽车的属性"
        self.make = make
        self.model = model
        self.year = year
        
    def get_descriptive_name(self):
        "返回整洁的描述性信息"
        long_name = f"{self.year} {self.make} {self.model}"
        return long_name.title()
my_new_car = Car('audi','a4',2019)
print(my_new_car.get_descriptive_name())
2019 Audi A4

9.2.2 给属性指定默认值

  • 创建实例时,有些属性无须通过形参来定义,可在方法_init_()中为其指定默认值

任务: 添加odometer_reading的属性,初始值为0,添加read_odometer()的方法,用于读取汽车的里程表

class Car:
    "模拟汽车"
    
    def __init__(self, make, model,year):
        "初始化,描述汽车的属性"
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0
        
    def get_descriptive_name(self):
        "返回整洁的描述性信息"
        long_name = f"{self.year} {self.make} {self.model}"
        return long_name.title()
    
    def read_odometer(self):
        "读取汽车里程"
        print(f"This car has {self.odometer_reading} miles on it.")
my_new_car = Car('audi','a4',2019)
print(my_new_car.get_descriptive_name())
my_new_car.read_odometer()
2019 Audi A4
This car has 0 miles on it.

9.2.3 修改属性的值

  • 直接通过实例修改
  • 通过方法进行设置
  • 通过方法进行递增(增加特定的值)
# 直接修改属性的值
class Car:
    "模拟汽车"
    
    def __init__(self, make, model,year):
        "初始化,描述汽车的属性"
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0
        
    def get_descriptive_name(self):
        "返回整洁的描述性信息"
        long_name = f"{self.year} {self.make} {self.model}"
        return long_name.title()
    
    def read_odometer(self):
        "读取汽车里程"
        print(f"This car has {self.odometer_reading} miles on it.")
        
my_new_car = Car('audi','a4',2019)
print(my_new_car.get_descriptive_name())

my_new_car.odometer_reading = 23
my_new_car.read_odometer()
2019 Audi A4
This car has 23 miles on it.
# 通过方法进行设置
class Car:
    "模拟汽车"
    
    def __init__(self, make, model,year):
        "初始化,描述汽车的属性"
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0
        
    def get_descriptive_name(self):
        "返回整洁的描述性信息"
        long_name = f"{self.year} {self.make} {self.model}"
        return long_name.title()
    
    def read_odometer(self):
        "读取汽车里程"
        print(f"This car has {self.odometer_reading} miles on it.")
        
    def updata_odometer(self, mileage):
        "将里程表读数设置为指定值"
        self.odometer_reading = mileage
        
        
my_new_car = Car('audi','a4',2019)
print(my_new_car.get_descriptive_name())

my_new_car.updata_odometer(23)
my_new_car.read_odometer()
2019 Audi A4
This car has 23 miles on it.
  • 可对方法updata_odometer()进行扩展,使其在修改里程表读数时做一些额外工作
    任务: 禁止任何人将里程表读数往回调
class Car:
    "模拟汽车"
    
    def __init__(self, make, model,year):
        "初始化,描述汽车的属性"
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0
        
    def get_descriptive_name(self):
        "返回整洁的描述性信息"
        long_name = f"{self.year} {self.make} {self.model}"
        return long_name.title()
    
    def read_odometer(self):
        "读取汽车里程"
        print(f"This car has {self.odometer_reading} miles on it.")
        
    def updata_odometer(self, mileage):
        "将里程表读数设置为指定值"
        "禁止将里程表读数往回调"
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can not roll back an odometer!")
            

my_new_car = Car('audi','a4',2019)
print(my_new_car.get_descriptive_name())

my_new_car.updata_odometer(23)
my_new_car.read_odometer()

my_new_car.updata_odometer(3)
my_new_car.read_odometer()
2019 Audi A4
This car has 23 miles on it.
You can not roll back an odometer!
This car has 23 miles on it.
# 通过方法对属性的值进行递增
class Car:
    "模拟汽车"
    
    def __init__(self, make, model,year):
        "初始化,描述汽车的属性"
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0
        
    def get_descriptive_name(self):
        "返回整洁的描述性信息"
        long_name = f"{self.year} {self.make} {self.model}"
        return long_name.title()
    
    def read_odometer(self):
        "读取汽车里程"
        print(f"This car has {self.odometer_reading} miles on it.")
        
    def updata_odometer(self, mileage):
        "将里程表读数设置为指定值"
        "禁止将里程表读数往回调"
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can not roll back an odometer!")
            
    def increment_odometer(self, miles):
        "将里程表读数增加指定的量"
        self.odometer_reading += miles
        
        
my_used_car = Car('subaru','outback',2015)
print(my_used_car.get_descriptive_name())

my_used_car.updata_odometer(23_500)
my_used_car.read_odometer

my_used_car.increment_odometer(100)
my_used_car.read_odometer()
2015 Subaru Outback
This car has 23600 miles on it.

9.3 继承

  • 编写类时,并非总是要从空白开始
  • 如果要编写的类时另一个现存的类的特殊版本,可以使用继承
  • 一个类继承另一个类时,将自动获得另一个类的所有属性和方法
  • 原有的类称为父类(Super-class),新的类称作子类(Sub-class)
  • 子类继承了父类所有的属性和方法,同时还可以定义自己的属性和方法

9.3.1 子类的方法_init_()

任务: 在前面创建的Car类的基础上创建新类ElectricCar,这样我们只需要为电动汽车特有的属性和行为编写代码。

class Car:
    "模拟汽车"
    
    def __init__(self, make, model,year):
        "初始化,描述汽车的属性"
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0
        
    def get_descriptive_name(self):
        "返回整洁的描述性信息"
        long_name = f"{self.year} {self.make} {self.model}"
        return long_name.title()
    
    def read_odometer(self):
        "读取汽车里程"
        print(f"This car has {self.odometer_reading} miles on it.")
        
    def updata_odometer(self, mileage):
        "将里程表读数设置为指定值"
        "禁止将里程表读数往回调"
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can not roll back an odometer!")
            
    def increment_odometer(self, miles):
        "将里程表读数增加指定的量"
        self.odometer_reading += miles
        
        
class ElectricCar(Car):
    "电动汽车的特殊之处"
    def __init__(self, make, model, year):
        "初始化父类属性"
        super().__init__(make, model, year)
        
        
my_tesla = ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
2019 Tesla Model S

9.3.2 给子类定义属性和方法

  • 子类继承父类后,可以给子类添加新属性和新方法

任务: 添加电动汽车特有的属性(电瓶),以及描述该属性的方法

-如果一个属性或方法是任何汽车都有而不是电动汽车特有的,应该添加到Car类而不是ElectricCar类中

class ElectricCar(Car):
    "电动汽车的特殊之处"
    def __init__(self, make, model, year):
        "先初始化父类属性"
        "再初始化电动汽车特有属性"
        super().__init__(make, model, year)
        self.battery_size =75
        
    def describ_barrery(self):
        "打印描述电瓶容量的消息"
        print(f"This car has a {self.battery_size}-Kwh battery.")
        

        
        
my_tesla = ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
my_tesla.describ_barrery()
2019 Tesla Model S
This car has a 75-Kwh battery.

9.3.3 重写父类的方法

  • 对于父类的方法,只要不符合子类模拟的实物的行为,都可以重写
  • 可以在子类中定义一个与重要的父类同名的方法,此时,Python不会考虑这个父类方法,只关注子类中定义的相应方法

9.3.4 将实例作为属性

  • 可将大类拆分为多个协同工作的小类

任务: 将电瓶的属性和方提取出来,放到一个Battery类中,并将一个Battery实例作为ElectricCar类的属性

class Car:
    "模拟汽车"
    
    def __init__(self, make, model,year):
        "初始化,描述汽车的属性"
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0
        
    def get_descriptive_name(self):
        "返回整洁的描述性信息"
        long_name = f"{self.year} {self.make} {self.model}"
        return long_name.title()
    
    def read_odometer(self):
        "读取汽车里程"
        print(f"This car has {self.odometer_reading} miles on it.")
        
    def updata_odometer(self, mileage):
        "将里程表读数设置为指定值"
        "禁止将里程表读数往回调"
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can not roll back an odometer!")
            
    def increment_odometer(self, miles):
        "将里程表读数增加指定的量"
        self.odometer_reading += miles
        
        
        
class Battery:
    "电动汽车电瓶"
    def __init__(self, battery_size =75):
        "初始化电瓶属性"
        self.battery_size = battery_size
        
    def describ_barrery(self):
        "打印描述电瓶容量的消息"
        print(f"This car has a {self.battery_size}-Kwh battery.")   
    
        
        
class ElectricCar(Car):
    "电动汽车的特殊之处"
    def __init__(self, make, model, year):
        "先初始化父类属性"
        "再初始化电动汽车特有属性"
        super().__init__(make, model, year)
        self.battery = Battery()
  

        
my_tesla = ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describ_barrery()
2019 Tesla Model S
This car has a 75-Kwh battery.

增添Battery类的优点:可将所有跟电瓶相关的属性和方法都放在该类中,而不会增导致EletricCar类混乱不堪

任务: 给Battery类添加一个方法,根据电瓶容量报告续航里程

class Car:
    "模拟汽车"
    
    def __init__(self, make, model,year):
        "初始化,描述汽车的属性"
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0
        
    def get_descriptive_name(self):
        "返回整洁的描述性信息"
        long_name = f"{self.year} {self.make} {self.model}"
        return long_name.title()
    
    def read_odometer(self):
        "读取汽车里程"
        print(f"This car has {self.odometer_reading} miles on it.")
        
    def updata_odometer(self, mileage):
        "将里程表读数设置为指定值"
        "禁止将里程表读数往回调"
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can not roll back an odometer!")
            
    def increment_odometer(self, miles):
        "将里程表读数增加指定的量"
        self.odometer_reading += miles
        
        
        
class Battery:
    "电动汽车电瓶"
    def __init__(self, battery_size =75):
        "初始化电瓶属性"
        self.battery_size = battery_size
        
    def describ_barrery(self):
        "打印描述电瓶容量的消息"
        print(f"This car has a {self.battery_size}-Kwh battery.")   
        
    def get_range(self):
        "打印电瓶的续航里程"
        if self.battery_size == 75:
            range = 260
        elif self.battery_size ==100:
            range = 315
            
        print(f"This car can go about {range} miles on a full charge.")
    
        
        
class ElectricCar(Car):
    "电动汽车的特殊之处"
    def __init__(self, make, model, year):
        "先初始化父类属性"
        "再初始化电动汽车特有属性"
        super().__init__(make, model, year)
        self.battery = Battery()
  

        
my_tesla = ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describ_barrery()
my_tesla.battery.get_range()
2019 Tesla Model S
This car has a 75-Kwh battery.
This car can go about 260 miles on a full charge.

9.3.5 模拟实物

  • 从较高的逻辑层面(而不是语法层面)如何使用代码表示实物

9.4 导入类

  • Python允许将类存储在模块中,然后在主程序中导入所需的模块

9.4.3 导入单个类

from car import Carbb  #打开模块car.py并导入Car类

my_new_car = Car('audi','a4',2019)
print(my_new_car.get_descriptive_name())

my_new_car.odometer_reading = 23
my_new_car.read_odometer()
    
2019 Audi A4
This car has 23 miles on it.

9.4.3 在一个模块中存储多个类

from car import ElectricCar

my_tesla = ElectricCar('tesla', 'model s', 2019)

print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()
2019 Tesla Model S
This car has a 75-kWh battery.
This car can go about 260 miles on a full charge.

9.4.4 从一个模块中导入多个类

from car import Car, ElectricCar

my_beetle = Car('volkswagen','beetle',2019)
print(my_beetle.get_descriptive_name())

my_tesla = ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
2019 Volkswagen Beetle
2019 Tesla Model S

9.4.5 导入整个模块

#module_name.ClassName
import car

my_beetle = car.Car('volkswagen','beetle',2019)
print(my_beetle.get_descriptive_name())

my_tesla = car.ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
2019 Volkswagen Beetle
2019 Tesla Model S

9.4.5 导入模块中所有类

  • from module_name import *

  • 不推荐

  • 需要从一个模块中导入多个类时,最好导入整个模块,然后用module_name.ClassName语法访问类

9.4.6 在一个模块中导入另一个模块

9.4.7 使用别名

from car import ElectricCar as EC

my_tesla = EC('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
2019 Tesla Model S

9.5 Python 标准库

  • Python 标准库是一组Python 版本时文件内置模块 ,在程序中可直接调用 且不需要用 pip 包管理工具从互联网上下载。

  • 第三方库则是其他程序员为了更好的实现某种目标,在实际开发中逐渐衍生出来的函数库。Python语言有超过12万个第三方库,覆盖信息技术几乎所有领域。

  • Stop Trying to Reinvent the Wheel(不要重复造轮子)

from random import randint

randint(1,6)
from random import choice
student = ['jack','tom','jim','mary']
first_up = choice(student)
print(f"请{first_up.title()}同学回答问题.")

总结

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值