Python继承机制:子类初始化、方法重写与属性组合详解
本文深入解析Python中的类继承机制,涵盖单继承与多继承的查找顺序。重点讲解如何在子类中通过super()调用父类__init__以初始化属性,以及如何通过同名方法定义实现父类方法的重写。此外,还介绍了将复杂属性(如电池类)提取为独立类并作为子类属性的组合设计模式,帮助优化代码结构。
继承
在面向对象编程中,创建新类时往往不需要从零开始。若新类是现有类的特定变体,可采用继承机制。Python支持单继承与多继承两种形式。
当一个类继承另一个类时,它将自动获得父类的所有属性和方法。原类被称为父类(或超类),新类称为子类。子类不仅拥有父类的全部功能,还可定义独有的属性和方法,从而有效减少类之间的代码冗余。
如何确定子类所继承的父类?
具体实现方式如下所示:
class Parent_1:
pass
class Parent_2:
pass
class sub1(Parent_1):#单继承
pass
#查看自己的父类
print(sub1.__bases__)
class sub2(Parent_1,Parent_2):#多继承
pass
#查看自己的父类
print(sub2.__bases__)(<class '__main__.Parent1'>,)
(<class '__main__.Parent1'>, <class '__main__.Parent2'>)多继承的优缺点
优点在于子类可同时继承多个父类的属性,最大化代码复用率。缺点则是可能降低代码可读性,因一个子类对应多个父类,逻辑关系较为复杂。
属性与方法查找顺序:
查找路径为:对象实例 > 子类 > 父类 > 父类的父类。
具体示例如下:
class Fu():
def f1(self):
print('Fu.f1')
def f2(self):
print('Fu.f2')
self.f1()#对象名.方法(),此时的self==objects
class son(Fu):
def f1(self):
print('son.f1')
objects=son()
objects.f2()依据上述查找顺序,系统首先在对象实例的空间内查找方法f2;若未找到,则转向子类空间查找;最后才在父类空间中查找。
Foo.f2
Bar.f1子类中的__init__方法
在基于现有类构建新类时,通常需要调用父类的__init__()方法。此举旨在初始化父类__init__中定义的所有属性,确保子类实例包含这些基础属性。
示例代码如下:
#定义一个父类Car,父类又名超类,名称super由此而来
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
#定义一个子类ELectricCar,创建子类时,父类必须包含在当前的文件,父类必须位于子类的前面
class ELectricCar(Car):#定义子类时,必须在圆括号内指定父类的名称
#方法__init__()接受创建Car实例所需的信息
def __init__(self,make,model,year):
print("__init__()方法被调用")
#让python调用Car类的方法__init__(),让子类创建的实例包含父类这个方法中定义的所有属性
super().__init__(make,model,year)#super是一个特殊函数,使我们能够调用父类的方法
my_tesla=ELectricCar('tesla','model s',2019)
print(my_tesla.make)
print(my_tesla.year)
print(my_tesla.model)
print(my_tesla.get_descriptive_name())__init__()方法被调用
tesla
2019
model s
2019 Tesla Model S上述代码旨在验证子类ELectricCar是否继承了父类Car的属性,但此时子类尚未定义其特有的属性和方法。
为子类定义专属属性和方法:
继承后,可在子类中添加区分其与父类差异的新属性和新方法。
以下代码添加了一个电动车特有的属性及描述该属性的方法:
沿用前述代码结构:
#定义一个父类Car,父类又名超类,名称super由此而来
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
#定义一个子类ELectricCar,创建子类时,父类必须包含在当前的文件,父类必须位于子类的前面
class ELectricCar(Car):#定义子类时,必须在圆括号内指定父类的名称
#方法__init__()接受创建Car实例所需的信息
def __init__(self,make,model,year):
print("__init__()方法被调用")
#让python调用Car类的方法__init__(),让子类创建的实例包含父类这个方法中定义的所有属性
super().__init__(make,model,year)#super是一个特殊函数,使我们能够调用父类的方法
self.battery_size=75
def describle_battery(self):
print(f"this car a {self.battery_size}-kwl battery")
my_tesla=ELectricCar('tesla','model s',2019)
print(my_tesla.get_descriptive_name())
my_tesla.describle_battery() 此时,子类中新增了专有属性describle_battery:
#__init__()方法被调用
2019 Tesla Model S
this car a 75-kwl battery接下来重点分析新添加的子类专有属性:
def __init__(self,make,model,year):
print("__init__()方法被调用")
#让python调用Car类的方法__init__(),让子类创建的实例包含父类这个方法中定义的所有属性
super().__init__(make,model,year)#super是一个特殊函数,使我们能够调用父类的方法
self.battery_size=75
def describle_battery(self):#关于子类ELectricCar特有的描述
print(f"this car a {self.battery_size}-kwl battery")self.battery_size=75是子类特有属性,因此定义在子类的__init__()方法中。基于子类ELectricCar创建的所有实例均包含此属性,而父类Car的实例则不包含。
子类的复杂程度无上限。在模拟子类ELectricCar时,可根据需求添加任意数量的属性和方法。
若某属性或方法适用于所有汽车(包括父类Car和子类ELectricCar),应将其置于父类Car中;若仅适用于子类,则置于子类中。这样,父类用户获得通用功能,子类用户获得特有功能。
重写父类的方法
若父类方法不符合子类所模拟实物的行为特征,可进行重写。具体做法是在子类中定义一个与父类方法同名的新方法。此时,Python将忽略父类方法,仅执行子类中定义的方法。
示例如下:
假设父类Car包含fill_gas_tank()方法,这对子类ELectricCar(电动车)而言无意义。若需重写,只需在子类中定义同名方法即可。
class Car:
---snip:
def fill_gas_tank(self):
self.fill_gas_tank=90
print(f"电瓶车邮箱尺寸的大小是{self.fill_gas_tank}")
class ELectricCar(Car):
--snip:
def fill_gas_tank(self):#与父类中该属性的方法名相同
print("this car doesn't need a gas tank!")
my_tesla=ELectricCar('tesla','model s',2019)
print(my_tesla.get_descriptive_name())
my_tesla.fill_gas_tank()重写后,输出结果将反映子类ELectricCar的行为。若不重写,则仍输出父类中不相关的属性行为。
#__init__()方法被调用
2019 Tesla Model S
this car doesn't need a gas tank!将实例用作属性
在模拟实物时,若类的属性和方法清单及文件过长,可将类的一部分提取为单独的类,将大型类拆分为多个协同工作的小类。
例如,若子类ELectricCar中关于电池的属性与方法过多,可将其提取为名为Battery的类,并将一个Battery实例作为子类ELectricCar的属性:
示例代码如下:
class Car:
--snip--
class Battery:#这里是重写一个类
def __init__(self,battery_size=10):#该默认值可设定也可不设定
self.battery_size=battery_size
def describle_battery(self):
print(f"this car has a {self.battery_size}-kwl battery")
class ELectricCar(Car):
def __init__(self,make,model,year):
super().__init__(make,model,year)
self.battery=Battery()#在子类ELectricCar新添加了一个名为battery的属性
#让python创建一个新的Battery实例,并将该实例赋给属性新创建的属性battery
my_tesla=ELectricCar('tesla','model s',2019)
#和上面描述电池容量是一样的方法
my_tesla.battery.describle_battery()#让python在实例my_tasla中查找属性battery,并对battery进行调用随后向Battery类添加一个方法,用于描述电动车的续航里程:
class Car:
--snip--
class Battery:
--snip--
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):
--snip--
my_tesla=ELectricCar('tesla','model s',2019)
my_tesla.battery.describle_battery()
my_tesla.battery.get_range()#在my_tesla实例中查找battery,self.battery=Battery(),对Battery进行调用#__init__被调用
this car has a 75-kwl battery
this car can go about 260 miles on a full charge本文关于Python重写方法和特殊构造方法的介绍到此结束,更多Python相关内容可搜索本站历史文章或继续浏览后续文章,感谢支持!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













