8.4、继承
一个类继承另一个类时,它将自动获得另一个类的所有的属性和方法;原有的类称为父类,而新类称为子类。子类继承了其父类的所有的属性和方法,同时还可以定义自己的属性和方法。
什么是继承?
继承是一种创建新的类的方式,新创建的叫子类,继承的叫父类、超类、基类。
特点:子类可以使用父类的属性
继承是类与类之间的关系
好处:减少代码的冗余、提高重用性
定义如下:
class DerivedClassName(BaseClassName):
<statement-1>
.
.
.
<statement-N>
父类定义在另一个模块中可以用下面方法继承
class DerivedClassName(modname.BaseClassName):
8.4.1、子类的__init__()方法
创建子类的实例时,Python首先需要完成的任务是给父类的所有属性赋值。为此,子类的方法__init__()需要父类施以援手。
比如,下面来模拟地动汽车。电动汽车是一种特殊的汽车,因此我们可以在前面创建的Car类的基础上创建新类ElectricCar,这样只需为电动汽车特有的属性和行为编写代码。
如下所示:
class Car():
"""模拟汽车 -> make :制作 ;model:模型;year:年份"""
def __init__(self,make,model,year):
"""初始化描述汽车的属性"""
self.make = make # 制作
self.model = model # 模型
self.year = year # 年份
self.odometer = 0
def get_read_odometer(self):
"""获取汽车的里程信息"""
print("此款"+self.make+self.model+
'型车已行驶'+str(self.odometer) + '公里')
def update_orometer(self,mileage):
"""
将里程表读数设置为指定的值
禁止将里程表数让回调
"""
if mileage >= self.odometer:
self.odometer = mileage
else:
print("您的操作无效")
def increment_odometer(self,miles):
"""将里程表读数增加指定的量"""
self.odometer += miles
def get_car_information(self):
"""返回一些描述汽车的信息"""
mesg_name = '生产于:'+str(self.year)+'年 --> 类型:'+self.make+' --> 型号:'+self.model
return mesg_name
def print_info(self):
"""打印汽车信息方法"""
return print(self.get_car_information())
class ElectricCar(Car):
"""电动汽车类"""
def __init__(self,make,model,year):
"""初始化父类的属性"""
super().__init__(make,model,year)
my_tesla = ElectricCar('小刀','no3',2030)
print(my_tesla.get_car_information())
运行结果:
生产于:2030年 --> 类型:小刀 --> 型号:no3
代码解析:
首先是Car类的代码,创建子类时,父类必须包含在当前文件中,且位于子类前面。定义子类时,必须在括号中指定父类的名称。方法init()接收创建Car实例所需的信息。
super()是一个特殊函数,帮助Python将父类和子类关联起来。这句代码就是调用ElectricCar的父类的方法init(),让ElectricCar实例报案父类的所有属性。
8.4.2、给子类定义属性和方法
让一个类继承另一个类后,可添加区分子类和父类所需的新属性和方法。
例如下面的例子添加一个电动汽车特有的属性(电瓶),以及一个描述该属性的方法。我们将存储电瓶容量,并编写一个打印电瓶描述的方法
class ElectricCar(Car):
"""电动汽车类"""
def __init__(self,make,model,year):
"""
初始化父类的属性
初始化父类的属性,再初始化电动车特有的属性
"""
super().__init__(make,model,year)
self.battery_value = 80
def get_battery(self):
"""获取电瓶容量信息"""
print('此辆电动汽车电量值为:'+str(self.battery_value)+'-kWh')
my_tesla = ElectricCar('小刀','no3',2030)
print(my_tesla.get_car_information())
my_tesla.get_battery()
运行结果:
生产于:2030年 --> 类型:小刀 --> 型号:no3
此辆电动汽车电量值为:80-kWh
模拟电动汽车时候,你可以根据所需的准确程度添加数量的属性和方法。如果一个属性或方法是任何汽车都有的,而不是电动汽车特有的,就应该将其加入到Car类而不是ElectricCar类中。这样,使用Car类的人将获得相应的功能,而ElectricCar类只包含处理电动汽车所特有的属性和行为的代码。
8.4.3、重写父类的方法
对于父类的方法,只要它不符合子类模拟的实物的行为,都可对其进行重写。为此,可在子类中定义一个这样的方法,即它与要重写的父类方法同名。这样,Python将不会考虑这个父类方法,而只关注你在子类中定义的相应方法。
假设Car类中有个方法,他对电动汽车没有意义,因此可以在子类中重写它。
class Car():
--略--
def fill_gas_tank(self):
"""模拟父类中fill_gas_tank()方法"""
print("父类--->这个汽车没有油箱!")
class ElectricCar(Car):
--略--
def fill_gas_tank(self):
"""模拟子类重写父类中的fill_gas_tank()方法"""
print("子类--->电动汽车没有油箱")
运行结果:
生产于:2030年 --> 类型:小刀 --> 型号:no3
此辆电动汽车电量值为:80-kWh
子类--->电动汽车没有油箱
小结:使用继承,可让子类保留从父类那里继承过来的精华,并剔除不需要的糟粕。
8.4.4、将实例作为属性
使用代码模拟实体实物时,你可能会发现自己给类添加的细节越来越多,属性和方法清单以及文件都越来越长。在这种情况下,可能需要将类的一部分作为一个独立的类提取出来。这样就可将大型的类拆分成多个协同工作的小类。
例如,不断给ElectricCar类添加细节时候,这样类中包含了很多专门针对汽车电瓶的属性和方法。这种情况下,我们可以将这些属性和方法提取出来,放到另一个名为Battery的类中,并将一个battery实例用作ElectricCar类的一个属性。
class Car():
--略--
class Battery():
"""一次模拟电动汽车电瓶的简单尝试"""
def __init__(self,battery_value = 70):
"""初始化电瓶的属性"""
self.battery_value = battery_value
def describe_battery(self):
"""打印电瓶容量的信息"""
print('这个电瓶电量:'+str(self.battery_value)+'-kWh')
class ElectricCar(Car):
"""电动汽车类"""
def __init__(self,make,model,year):
"""
初始化父类的属性
初始化父类的属性,再初始化电动车特有的属性
"""
super().__init__(make,model,year)
self.battery = Battery() # 是电瓶类
# 测试方法
my_tes = ElectricCar('劳斯莱斯','野牛3号',2020)
print(my_tes.get_car_information())
my_tes.battery.describe_battery()
运行结果:
生产于:2020年 --> 类型:劳斯莱斯 --> 型号:野牛3号
这个电瓶电量:70-kWh
代码解析:
首先定义了一个叫Battery的类,它没有继承任何类。此类中初始化方法中的形参,除了self之外,还有另一个形参是battery_value。这个形参是可选的,如果调用时没有给传递参数,则显示默认值。并且describe_battery()方法也移到这个类中。
在ElectricCar类中初始化方法中,添加了一个名叫self.batttery的属性。self.battery = Battery()
此行代码是先创建一个新的Battery实例,并将实例存储到self.battery
中。每当方法init()被调用时,都将执行该操作。因此现在每个ElectricCar实例都包含一个自动创建的Battery实例。
这时我们创建了一辆电动汽车,并将其存到变量my_tes中。要想描述电瓶时,就需要使用电瓶汽车的属性battery(my_tes.battery.describe_battery()
),此行代码就是让Python在实例my_tes中查找属性battery,并对存在该属性中的Battery实例调用方法describe_battery()方法。
这样做的目的主要是为了让代码更加清晰、整洁。
下面再给Battery类添加一个方法,他根据电瓶容量报告汽车的续航里程:
class Car():
--略--
class Battery():
"""一次模拟电动汽车电瓶的简单尝试"""
--略--
def get_range(self):
"""获取电瓶的续航里程"""
if self.battery_value == 70:
range = 240
elif self.battery_value == 85:
range = 270
message = '此电瓶续航 '+str(range)
message += ' -公里'
print(message)
class ElectricCar(Car):
"""电动汽车类"""
--略--
my_tes = ElectricCar('劳斯莱斯','野牛3号',2020)
print(my_tes.get_car_information())
my_tes.battery.describe_battery()
my_tes.battery.get_range()
运行结果:
生产于:2020年 --> 类型:劳斯莱斯 --> 型号:野牛3号
这个电瓶电量:70-kWh
此电瓶续航 240 -公里
共勉:
每天进步一点点