在 Python 中,继承是一种面向对象编程(OOP)的特性,它允许一个类(子类)继承另一个类(父类)的属性和方法。继承可以促进代码重用,提高程序的可维护性。以下是继承的基本概念
一、基本概念
1. 父类(基类):被继承的类。
2. 子类(派生类):继承父类的类。
3. 单继承与多继承:
单继承:子类仅继承一个父类。
多继承:子类可以继承多个父类。
二、单继承
语法:
class A():
A属性
A方法
class B(A):
B属性
B方法
B继承A,B可以获取A的属性和方法进行使用,促进代码的重用。
# Person父类
class Person(object):
# 构造函数
def __init__(self, name, age, nationality):
self.name = name
self.age = age
self.nationality = nationality
# 打招呼方法
def sayHi(self):
print(f'我叫{self.name},今年{self.age},来自{self.nationality}')
# 中国人
class Chinese(Person):
pass
sq = Chinese('孙权',18,'中国')
sq.sayHi()
# 美国人
class America(Person):
pass
tom = America('汤姆',15,'美国')
tom.sayHi()
三、多继承
语法:
class A():
A属性
A方法
class B():
B属性
B方法
class C(A,B):
C属性
C方法
C同时继承A、B,可以获得A、B的属性和方法进行使用
class Father():
def PaternalPropety(self):
print('父亲财产')
def Paternallineage(self):
print('父亲血统')
class Mother():
def MaternalPropety(self):
print('母亲财产')
def MaternalLineage(self):
print('母亲血统')
# 继承Father、Mother类
class Child(Father,Mother):
pass
# 实例化Child对象
child = Child()
# 获得继承的两个类的方法属性
child.PaternalPropety()
child.MaternalPropety()
child.MaternalLineage()
child.MaternalLineage()
四、重写
方法重写是指子类可以定义与父类同名的方法,从而替代父类中的实现。通过重写,子类能够提供特定于自己的方法实现,而不是使用父类中定义的版本。这是面向对象编程中多态性的一部分,有助于实现更灵活的代码设计。
何时使用方法重写:
当子类需要修改或扩展父类的行为时。
当子类有特定的逻辑,而这逻辑在父类中不适用时。
想要在子类中实现不同的功能,但保留同名的方法以便于接口一致。
1. 方法签名相同的关键点
子类中重写的方法应与父类中要重写的方法具有相同的名称和参数列表。
案例:
重写sayHello()方法,不同国家的人有不同打招呼的习惯
# Person父类
class Person(object):
# 构造函数
def __init__(self, name, age, nationality):
self.name = name
self.age = age
self.nationality = nationality
# 自我介绍
def sayHi(self):
print(f'我叫{self.name},今年{self.age},来自{self.nationality}')
# 打招呼
def sayHello(self):
print('打招呼')
# 中国人
class Chinese(Person):
def sayHello(self):
print('吃饭了吗,您!')
sq = Chinese('孙权', 18, '中国')
sq.sayHello()
# 美国人
class America(Person):
def sayHello(self):
print('Good morning')
tom = America('汤姆', 15, '美国')
tom.sayHello()
2. super() 的使用
在 Python 中,`super()` 是一个内置函数,用于调用父类的构造函数或方法。它使得子类可以继承父类的方法,同时在子类的重写方法中方便地访问父类的方法。使用 `super()` 可以帮助保持父类的逻辑,而又允许子类添加或修改一些特定的实现。
特性和优点:
(1)提高代码的可维护性:使用 `super()` 可以在重写方法时,轻松访问和延续父类的方法逻辑,减少冗余代码。
(2)支持多重继承:`super()` 支持在多继承的环境中正确调用父类的方法,避免直接引用父类而可能导致的问题。
(3)简化代码:使用 `super()` 函数可以省略子类中对父类名称的明示引用,从而使代码更干净。
构造函数调用:
(1)在子类的构造函数中使用 `super().__init__()` 调用父类的构造函数。
(2)方法重写时调用父类方法:
在子类的方法中,可以使用 `super().<方法名>()` 来调用父类中的 method。
案例:
# Person父类
class Person(object):
# 构造函数
def __init__(self, name, age, nationality):
self.name = name
self.age = age
self.nationality = nationality
# 自我介绍
def sayHi(self):
print(f'我叫{self.name},今年{self.age},来自{self.nationality}')
# 打招呼
def sayHello(self):
print('打招呼')
# 中国人
class Chinese(Person):
def __init__(self, name, age, nationality, nation):
# 重点1:调用父类的构造函数,初始化对象
super().__init__(name, age, nationality)
# 子类的民族属性
self.nation = nation
# 重点2:重写父类的sayHi()方法
def sayHi(self):
# super调用父类的sayHi()方法
super().sayHi()
# 重写父类的sayHello()方法
def sayHello(self):
print('吃饭了吗,您!')
# 实列化对象
sq = Chinese('孙权', 18, '中国','壮族')
sq.sayHi() #我叫孙权,今年18,来自中国
sq.sayHello() #吃饭了吗,您!
小结
使用 `super()` 可以在子类中方便地访问和调用父类的方法和构造函数。这种做法不仅使得代码更易于维护,还提供了对多继承中的一致性支持。通过 `super()`,你能够在重写父类方法时保留父类逻辑,同时在子类中实现特定的行为,是编写清洁且高效代码的重要工具。
五、方法解析顺序(MRO, Method Resolution Order)
方法解析顺序(MRO)是指在多继承情况下,Python 确定调用方法的顺序。它决定了在类层次结构中搜索方法或属性的路径。当一个方法被调用时,Python 根据类的继承关系遵循特定的顺序来查找这个方法,确保正确的顺序执行。
1. MRO 的重要性
避免重复执行:MRO 确保父类的每个方法只执行一次,防止方法的重复执行。
解决命名冲突:当多个父类有相同的方法或属性时,MRO 决定了优先调用哪个父类的方法或属性。
支持多继承:在多重继承环境中,MRO 能够清晰地指明方法查找的顺序,以避免混淆。
2. MRO 的规则
Python 使用 C3 线性化算法来计算 MRO。这个算法遵循以下规则:
从子类向父类:首先搜索子类自身的方法,如果找不到,则向父类搜索。
优先顺序:在 MRO 中,基于继承顺序来确定父类的优先级。
规范顺序:如果多个父类同级,遵循从左至右的顺序进行搜索。
3. 查看 MRO
每个类都可以通过 `__mro__` 属性或 `mro()` 方法查看其方法解析顺序。
# Person父类
class Person(object):
# 构造函数
def __init__(self, name, age, nationality):
self.name = name
self.age = age
self.nationality = nationality
# 打招呼方法
def sayHi(self):
print(f'我叫{self.name},今年{self.age},来自{self.nationality}')
class Father(Person):
def PaternalPropety(self):
print('父亲财产')
def Paternallineage(self):
print('父亲血统')
class Mother():
def MaternalPropety(self):
print('母亲财产')
def MaternalLineage(self):
print('母亲血统')
# 继承Father、Mother类
class Child(Father,Mother):
pass
# # 实例化Child对象
# child = Child()
print(Child.__mro__)
'''
#结果:
(<class '__main__.Child'>, <class '__main__.Father'>, <class '__main__.Person'>, <class '__main__.Mother'>, <class 'object'>)
'''
在这个例子中:
`Child` 的 MRO 是 `[Child, Father, Mather, Person, object]`,这意味着在搜索 `Child` 的方法时,Python 会首先查找 `Child`,然后查找 `Father`,接着查找 `Mather`,然后查找 `Person`,最后查找基类 `object`。
小结
方法解析顺序(MRO)是 Python 多继承机制的重要组成部分,它决定了在类层次结构中查找方法的顺序。了解 MRO 规则能够帮助开发者在复杂的类继承结构中作出更清晰的设计决策,并有效避免潜在的命名冲突和逻辑错误。在 Python 中使用 `__mro__` 或 `mro()` 方法,可以方便地查看任何类的 MRO。
六、总结
继承是 Python 中面向对象编程的重要特性。通过继承,可以创建更具层次结构的类结构,实现代码的复用和扩展。无论是单继承还是多继承,都可以通过方法重写和构造函数的重用来增强类的功能。这样可以使代码更加清晰、更易于维护。