知识补充3:Python——类的继承

类的基础

class Dog:
    # 从空白中创建这个类,所以定义中没有圆括号
    # 类的首字母要大写
    def __init__(self, name, age):
        # init两边各两个下划线,这是一种特殊方法
        # 这个方法定义成包含三个形参(首位必须有且为self)
        # 根据Dog类创建新实例时,这个方法会自动调用,并自动传入实参self
        # 只需给后面的形参(name和age)提供值
        # 每个与实例相关联的方法调用都自动传递实参self,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法
        self.name = name
        self.age = age
        # 以self为前缀的变量可供类中所有方法使用
        # 还可以通过类的任何实例来访问(这类的变量称为属性)

    def sit(self):
        # 这个方法不需要额外的信息,所以只有一个形参self
        print(f"{self.name} is now sitting.")

    def roll_over(self):
        print(f'{self.name} rolled over!')


jack = Dog('Jack', 18)
# 创建实例
jack.name
# 访问属性
jack.sit()
jack.roll_over()
# 调用方法

类的属性 

class User:
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name
        self.age = 18
        # 指定默认属性值

    def describe_user(self):
        print(self.first_name, self.last_name)

    def greet_user(self):
        print(f'Hello, {self.first_name} {self.last_name}')

    def update_age_1(self, age):
        if age >= self.age:
            self.age = age
        else:
            print('新设置的年龄不能比之前的小')

    def update_age_2(self, age):
        self.age += age

    def update_age_3(self):
        self.age += 1


myself = User('Hugo', 'Ho')
myself.describe_user()
myself.greet_user()
print(myself.age)
myself.age = 20
print(myself.age)
# 直接修改属性的值
myself.update_age_1(29)
print(myself.age)
# 通过方法修改属性的值
myself.update_age_2(11)
print(myself.age)
# 通过方法对属性的值进行递增(自定义值)
myself.update_age_3()
print(myself.age)
# 通过方法对属性的值进行递增(固定值)

类的继承

在编写类时,可以从空白开始,也可以使用继承(新建类是现成类的一个特殊版本)。

  • 一个类继承另一个类时,将自动获得另一个类的所有属性和方法(还可以定义自己的属性和方法)。
  • 原有的类称为父类,而新建的类称为子类。

子类的方法__init__()

在父类的基础上编写子类时,通常要调用父类的方法__init__()。这将初始化在父类__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 update_odometer(self, mileage):
        """
        将里程表读数设置为指定的值。
        禁止将里程表读数往回调。
        """
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print('You can`t roll back an odometer!')

    def increment_odometer(self, miles):
        """将里程表读数增加指定的量"""
        self.odometer_reading += miles


class ElectricCar(Car):
# 定义子类时,必须在圆括号内指定父类的名称
    """电动汽车的独特之处。"""

    def __init__(self, make, model, year):
    # 方法__init__()接收创建Car实例所需的信息
        """初始化父类的属性"""
        super().__init__(make, model, year)
        # super()是一个特殊函数,可以实现对父类方法的调用
        # 这里super()函数调用了Car类的方法__init__(),让ElectricCar实例包含这个方法中定义的所有属性
        # 父类也称为超类(superclass),名称super由此而来


my_tesla = ElectricCar('tesla', 'model s', 2019)
# 创建一个ElectricCar实例,并将其赋给变量my_tesla
# 这行代码会自动调用子类ElectricCar中定义的方法__init__(),后者会让Python调用父类Car中定义的方法__init__()
print(my_tesla.get_descriptive_name())

输出:

2019 Tesla Model S

给子类定义属性和方法

在子类继承父类后,就可以添加要和父类区分所需的新属性和新方法了。

class Car:
    --snip--

class ElectricCar(Car):
    """电动汽车的独特之处。"""

    def __init__(self, make, model, year):
        """
        初始化父类的属性。
        初始化子类特有的属性。
        """
        super().__init__(make, model, year)
        self.battery_size = 75
        # 添加子类的新属性(根据ElectricCar类创建的实例都包含该属性,其他Car类的实例不包含)

    def describe_battery(self):
    # 添加子类的新方法
        """打印一条描述电池容量的消息。"""
        print(f"This car has a {self.battery_size}-kWh battery.")


my_tesla = ElectricCar('tesla', 'model s', 2019)
# 创建一个ElectricCar的实例
print(my_tesla.get_descriptive_name())
# 调用子类从父类继承过来的方法
my_tesla.describe_battery()
# 调用子类自己定义的方法

输出:

2019 Tesla Model S
This car has a 75-kWh battery.

重写父类的方法

可在子类中定义一个与要重写的父类方法同名的方法。

class Car:
    --snip--

class ElectricCar(Car):
    """电动汽车的独特之处。"""

    def __init__(self, make, model, year):
        """
        初始化父类的属性。
        初始化子类特有的属性。
        """
        super().__init__(make, model, year)
        self.battery_size = 75

    def describe_battery(self):
        """打印一条描述电池容量的消息。"""
        print(f"This car has a {self.battery_size}-kWh battery.")

    def get_descriptive_name(self):
        """返回完整的描述性信息(带新能源标识)。"""
        long_name = f'[新能源] {self.year} {self.make} {self.model}'
        # 重写父类中的同名方法并加上“[新能源]”标识
        return long_name.title()


my_tesla = ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
# 此时Python不再考虑父类方法,而只关注子类中定义的相应方法
my_tesla.describe_battery()

[新能源] 2019 Tesla Model S
This car has a 75-kWh battery.

将实例用作属性

可以将类的一部分提取出来,作为一个独立的类(将大型类拆分成多个协同工作的小类)。

下面将ElectricCar的部分属性和方法提取出来,放到一个名为Battery的类中,并将一个Battery实例作为ElectricCar类的属性。

class Car:
    --snip--

class ElectricCar(Car):
    """电动汽车的独特之处。"""

    def __init__(self, make, model, year):
        """
        初始化父类的属性。
        初始化子类特有的属性。
        """
        super().__init__(make, model, year)
        self.battery = Battery()
        # 添加新属性,连接Battery类(创建一个Battery类的实例,每当方法__init__被调用时,都将执行该操作)
        # 现在每个ElectricCar实例都包含一个自动创建的Battery实例

    def get_descriptive_name(self):
        """返回完整的描述性信息(带新能源标识)。"""
        long_name = f'[新能源] {self.year} {self.make} {self.model}'
        return long_name.title()


class Battery:
# 定义一个名为Battery的新类(没有继承任何类)
    """电动车电池的相关属性和方法。"""

    def __init__(self, battery_size=75):
    # 加入形参battery_size,如果没有提供值,电池容量默认就是75
        """初始化电瓶的属性"""
        self.battery_size = battery_size

    def describe_battery(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.battery.describe_battery()
# 描述电瓶的时候,需要使用ElectricCar类的属性battery

输出: 

[新能源] 2019 Tesla Model S
This car has a 75-kWh battery.

修改实例(类)的实例(属性)的值

class Car:
    --snip--

class ElectricCar(Car):
    --snip--

class Battery:
    --snip--

my_tesla = ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
my_tesla.battery.battery_size = 100
# 通过修改ElectricCar的实例(my_tesla)中的属性(battery)中的属性(battery_size)的值
my_tesla.battery = Battery(100)
# 通过修改ElectricCar的实例(my_tesla)中的属性(battery)对应的实例(Battery)的参数值
my_tesla.battery.describe_battery()

输出:

[新能源] 2019 Tesla Model S
This car has a 100-kWh battery.

 一辆车是由很多模块组成的,如果想要对每个模块都进行详尽的描述,那最好就是将不同模块安排在不同的类里面,然后再把这些类以实例的形式插入到一个总类的属性里面,需要的时候再调用就好了。

下面再给Battery类添加一个方法,它能根据电瓶容量报告汽车的续航里程。

class Car:
    --snip--

class ElectricCar(Car):
    --snip--

class Battery:
    """电动车电池的相关属性和方法。"""

    def __init__(self, battery_size=75):
        """初始化电瓶的属性"""
        self.battery_size = battery_size

    def describe_battery(self):
        """打印一条描述电池容量的消息。"""
        print(f"This car has a {self.battery_size}-kWh battery.")

    def get_nedc(self):
    # 新增方法作简单的分析,根据电池容量报告续航里程
        """打印一条消息,描述电瓶的续航里程"""
        if self.battery_size == 75:
            nedc = 260
        elif self.battery_size == 100:
            nedc = 315
        print(f"This car can go about {nedc} miles on a full charge.")


my_tesla = ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
# my_tesla.battery.battery_size = 100
my_tesla.battery.describe_battery()
my_tesla.battery.get_nedc()
# 通过调用实例的属性的方法来获取信息

输出:

[新能源] 2019 Tesla Model S
This car has a 75-kWh battery.
This car can go about 260 miles on a full charge.

类的导入

从一个模块中导入多个类

from car import Car, ElectricCar


my_beetle = Car('volkswagen', 'beetle', 2019)

my_tesla = Car('tesla', 'roadster', 2019)

导入整个模块

import Car

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

my_tesla = car.ElectricCar('tesla', 'roadster', 2019)

导入模块中所有的类

from car import *
# 不推荐使用
# 不能一目了然清楚使用了模块里面的哪些类
# 引发名称方面的迷惑(如果出现同名的类会产生错误)
# 推荐使用导入整个模块,然后用“模块名.类名”的语法来访问类

导入类并指定别名

from electric_car import ElectricCar as EC

my_tesla = EC('tesla', 'roadster', 2019)

类的编码风格

  • 类名采用驼峰命名法:每个单词的首字母大写,不使用下划线(实例名和模块名使用小写格式,单词之间加入下划线)
  • 类定义的后面和模块的开头都跟上简要描述类功能的文档字符串
  • 在模块中,两个类之间空两行。在类中,两个方法之间空一行。
  • 先导入标准库的模块再导入自行编写的模块

<完>

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值