python支持多继承吗_Python 中如何实现多继承?以及多继承会带来什么问题?

微信号:Demon-5203

如有问题欢迎后台留言或加微信

加微信,可进入无广告编程学习群,免费共享学习资源

题目:Python 中如何实现多继承?以及多继承会带来什么问题?

扩展题目:你了解 Python 中的 MRO 列表吗?

上篇文章,我们遗留了一个问题,就是 Python 中的多继承问题。今天进行详细介绍。首先看下昨天的代码:

class Base(object):

def __init__(self):

print("enter Base")

print("leave Base")

class A(Base):

def __init__(self):

print("enter A")

super(A, self).__init__()

print("leave A")

class B(Base):

def __init__(self):

print("enter B")

super(B, self).__init__()

print("leave B")

class C(A, B):

def __init__(self):

print("enter C")

super(C, self).__init__()

print("leave C")

c = C()

"""执行结果如下:enter Center Aenter Benter Baseleave Baseleave Bleave Aleave C"""

正常按照我们学 JAVA 的思路(虽然 JAVA 里并不能同时 extends 两个类,但假定它即便把它看成是一个单一继承,输出也是不一样的),代码输出应该是:

/*

enter C

enter A

enter Base

leave Base

leave A

enter B

enter Base

leave Base

leave B

leave C

*/

之所以会出现这种结果,是因为在 Python 中有一个列表叫 MRO,它的全称是 Method Resolution Order,即方法解析顺序列表。对于我们定义的每个类,它都会根据一种特定的算法(C3线性算法,这里不作深入讨论)来得到一个列表,这个列表代表了类继承的顺序。我们可以通过 mro() 方法来查看某个类的 MRO 列表:

C.mro() # 通过 类名. 来获得

c.__class__.mro() # 通过 实例对象.__class__ 来获得

c().__class__.mro() # 通过 实例对象.__class__ 来获得

"""

得到的 MRO 列表:

[multi_extends_test01.C,

multi_extends_test01.A,

multi_extends_test01.B,

multi_extends_test01.Base,

object]

"""

从结果我们可以看出,一个类的 MRO 列表会包含它所有父类的 MRO 列表,即父类的 MRO 列表其实是子类的一个真子集。而 super() 的执行就是根据这个列表而来的。下面让我们来仔细看下 super() 这个方法,它接受两个参数,第一个参数是当前子类的名称,第二个参数是 self ,它是一个固定参数,代表的是当前的实例对象。super() 执行的过程可以总结为两步:根据我们传入的实例对象,通过 instance.__class__.mro() 得到当前类的 MRO 列表

根据列表的顺序,取列表的第二个元素,返回

这样就能解释之前的代码为什么会这样输出了。关键点在于我们是通过实例对象来获取到的 MRO 列表,而在整个继承的过程中,其实实例对象是没有发生改变的。它一直是类C的实例对象。这里用代码注释的形式给大家分解下步骤:

class Base(object):

def __init__(self): # 11. 进入 Base.__init__

print("enter Base") # 12. 打印 enter Base

print("leave Base") # 13. 打印 leave Base

class A(Base):

def __init__(self): # 5. 进入 A.__init__

print("enter A") # 6. 打印 enter A

# 7. 这里将分为两步执行

# 7.1 执行 c.__class__.mro

# 7.2 返回 MRO 列表中的第二个元素,也就是 Base

super(A, self).__init__()

print("leave A") # 15. 打印 leave A

class B(Base):

def __init__(self): # 8. 进入 B.__init__

print("enter B") # 9. 打印 enter B

# 10. 这里将分为两步执行

# 10.1 执行 c.__class__.mro

# 10.2 返回 MRO 列表中的第二个元素,也就是 B

super(B, self).__init__()

print("leave B") # 14. 打印 leave A

class C(A, B):

def __init__(self): # 2. 实例 C ,会进入 __init__

print("enter C") # 3. 打印 enter C

# 4. 这里将分为两步执行

# 4.1 执行 c.__class__.mro

# 4.2 返回 MRO 列表中的第二个元素,也就是 A

super(C, self).__init__()

print("leave C") # 16. 打印 leave A

c = C() # 1. 首先代码会从这里开始执行。

"""

enter C

enter A

enter B

enter Base

leave Base

leave B

leave A

leave C

"""

其实 super() 的调用过程,有点递归的味道。最后一个问题来了,为什么 Python 要设置一个 MRO 列表来规定继承中类的执行顺序呢?这是因为像我之前学过的 JAVA 语言,它是单继承的,一个属性方法的调用是十分明确的。而在 Python 中,是多继承的,如果父类中存在同名函数的时候,是会产生二义性的,MRO 就是用来处理这种问题的。它有三个原则:子类一定在父类前面

如果存在多个父类,它会根据 MRO 列表顺序来执行

如果多个父类存在相同方法,会根据 MRO 列表选择第一个符合的类

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值