Python语言中,要实现类的多重继承,只要在定义类的时候,在圆括号中以逗号分隔多个父类即可
# Python支持多重继承,也就是一个类可以从多个基类那里继承属性
# class ChildClass(ParentClass1,ParentClass2...):
# pass
Python多重继承举例
# 父类1 - 人类
class Person:
def __init__(self, name, sex, age):
self._name = name
self._sex = sex
self._age = age
# 父类2 - 程序员类
class Programer:
def work(self):
self._work()
def _work(self):
print("coding and coding, day by day!")
# Python程序员类
# 从Person类继承_name,_age
# 从Programer类继承work
class Pythonor(Person, Programer):
def _work(self):
print(f"{self._name} has been coding {self._age} years in python world")
# 实例化
luxp = Pythonor("老六", "男", 28)
luxp.work()
从上面这个例子中可以看到 Pythoner
类继承自Person
类及Programer
类,当实例化的时候,执行的是Person
类的__init__
方法,work()
则是Programer
类的方法
多重继承的顺序
我们不难想到,如果一个类继承的父类,都包含着一个同名的方法,那么当子类执行父类该方法时,应该继承谁的?
多重继承顺序举例
class A:
def do(self):
print("A")
class B:
def do(self):
print("B")
class C(A,B):
pass
c = C()
c.do()
# 输出 A
# D调整了继承顺序
class D(B,A):
pass
d = D()
d.do()
# 输出B
# 继承顺序是从左到右搜索,一旦搜索到方法后停止搜索
由此类可见,继承顺序是从左到右搜索,一旦搜索到方法后停止搜索
更复杂一点的多重继承
# 更加复杂的多重继承
class A:
def do(self):
print("A")
class B:
def do(self):
print("B")
class C(A):
pass
class D(B):
def do(self):
print("D")
class E(C,D):
pass
e = E()
e.do()
# 输出 A
在这个例子中, E类继承自C类、D类,C类继承自A类,D类继承自B类,C类没有do方法,D类有do方法,然而最后输出的是A,这说明E类在寻找继承方法的时候,是从左开始,然后顺着左侧的继承树往上查找,直到找到,如果找不到,就会往右找,这种规则就是:
- 广度优先 - 先从左往右开始
- 深度优先 - 从某一侧往父级方向查找,直到这一侧遍历完成,再向右侧查找
菱形继承
就是类的多个父类继承自同一个父类,这样形成一个菱形,比如所有的类都是来自object
class GrandpaClass:
def do(self):
self._show_me()
def _show_me(self):
print(self.__class__)
class FatherClass(GrandpaClass):
pass
class UncleClass(GrandpaClass):
def _show_me(self):
print("hello, class name is", self.__class__)
class ChildClass(FatherClass, UncleClass):
pass
zhangsan = ChildClass()
zhangsan.do()
__mro__ - 顺序线性化
实际上,类的方法继承顺序是动态的,因为多重继承带来的复杂性可能超出了想象,如果每一次都要人为的去考虑继承顺序,会给编程工作带来很大困扰,Python的多重继承事实采用了一种叫C3的算法,从而将各种继承顺序以线性顺序的方法表达出来,可以通过类属性__mro__查看
# __mro__提供了一个元组序列,该序列反映了继承顺序
print(E.__mro__)
# 输出
# (__main__.E, __main__.C, __main__.A, __main__.D, __main__.B, object)
print(ChildClass.__mro__)
super-获得超类的方法
# super([type[, object-or-type]])
super返回一个代理对象,它会将方法调用委托给 type 指定的父类或兄弟类,指定的顺序依据__mro__属性
如果不带任何参数,则将方法绑定到默认的第一个父类
如果传参, 第二个参数必须是第一个参数的实例或者子类, 然后方法按照__mro__顺序绑定到type之后的某个类
单继承中的super用法
假设子类中有__init__方法,同时又需要执行父类的__init__方法,如果不使用super,代码如下
class Person:
def __init__(self, name, age, sex):
self._name = name
self._age = age
self._sex = sex
def show(self):
print(f"name:{self._name}, age:{self._age}, sex:{self._sex}")
class Man(Person):
__sex = "MAN"
def __init__(self, name, age):
# 调用父类的__init__方法
Person.__init__(self, name, age, self.__sex)
zhangsan = Man("zhangsan", 28)
zhangsan.show()
在Man类中__init__
方法中通过Person.__init__
的方式执行了父类的__init__,需要注意的是传入了参数self
super()使用举例
# 使用super执行父类方法
class Woman(Person):
__sex = "WOMAN"
def __init__(self, name, age):
super().__init__(name, age, self.__sex)
cuihua = Woman("cuihua", 18)
cuihua.show()
这里使用了super().__init__
方式,没有传入self
参数,这种方式可以防止父类改名引起的不必要的麻烦:如果多处使用父类方法,就需要修改多处
多重继承中使用super举例
在多继承中可以通过向super传入参数来限制继承搜索路径
class A:
def show(self):
print(A)
class B:
def show(self):
print(B)
class C(A):
def show(self):
print(C)
class D(B):
def show(self):
print(D)
class E(C, D):
def show(self):
print(E.__mro__)
super().show()
print("*"*10)
super(A, self).show()
e = E()
e.show()
# 输出
# mro顺序
# (<class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class '__main__.D'>, <class '__main__.B'>, <class 'object'>)
# super().show()
# <class '__main__.C'>
# super(A,self).show()
# <class '__main__.D'>
# super的第一个参数改为C
class E(C, D):
def show(self):
print(E.__mro__)
super().show()
print("*"*10)
super(C, self).show()
e = E()
e.show()
# 当super传入相应参数的时候,可以在类外部使用
super(C, e).show()
super(A,self)
得到的是D
类,从mro顺序中可以看到A后面的是D
讨论区