题目:Python 中如何实现多继承?以及多继承会带来什么问题?
扩展题目:你了解 Python 中的 MRO 列表吗?
上篇文章,我们遗留了一个问题,就是 Python 中的多继承问题。今天进行详细介绍。首先看下昨天的代码:
正常按照我们学 JAVA 的思路(虽然 JAVA 里并不能同时 extends 两个类,但假定它即便把它看成是一个单一继承,输出也是不一样的),代码输出应该是:
之所以会出现这种结果,是因为在 Python 中有一个列表叫 MRO,它的全称是 Method Resolution Order,即方法解析顺序列表。对于我们定义的每个类,它都会根据一种特定的算法(C3线性算法,这里不作深入讨论)来得到一个列表,这个列表代表了类继承的顺序。我们可以通过 mro() 方法来查看某个类的 MRO 列表:
从结果我们可以看出,一个类的 MRO 列表会包含它所有父类的 MRO 列表,即父类的 MRO 列表其实是子类的一个真子集。而 super() 的执行就是根据这个列表而来的。下面让我们来仔细看下 super() 这个方法,它接受两个参数,第一个参数是当前子类的名称,第二个参数是 self ,它是一个固定参数,代表的是当前的实例对象。super() 执行的过程可以总结为两步:
根据我们传入的实例对象,通过 instance.__class__.mro() 得到当前类的 MRO 列表
根据列表的顺序,取列表的第二个元素,返回
这样就能解释之前的代码为什么会这样输出了。关键点在于我们是通过实例对象来获取到的 MRO 列表,而在整个继承的过程中,其实实例对象是没有发生改变的。它一直是类C的实例对象。这里用代码注释的形式给大家分解下步骤:
其实 super() 的调用过程,有点递归的味道。最后一个问题来了,为什么 Python 要设置一个 MRO 列表来规定继承中类的执行顺序呢?这是因为像我之前学过的 JAVA 语言,它是单继承的,一个属性方法的调用是十分明确的。而在 Python 中,是多继承的,如果父类中存在同名函数的时候,是会产生二义性的,MRO 就是用来处理这种问题的。它有三个原则:
子类一定在父类前面
如果存在多个父类,它会根据 MRO 列表顺序来执行
如果多个父类存在相同方法,会根据 MRO 列表选择第一个符合的类
愿关注我们的人都能找到
属于自己的皮球
领取专属 10元无门槛券
私享最新 技术干货