python2和python3中使用super的区别
super只能用在新式类中。在python3中的所有类都是新式类,而在python2继承object的才是新式类。
1 | # python3 |
python3可以直接使用super().xxx代替super(Class, self).xxx
1 | # python3 |
单继承
在单继承中的super是主要用来调用父类的方法的。
1 | class A: |
执行以下代码
1 | b = B() |
执行结果如下
1 | A.foo <__main__.B object at 0x000001548A54D828> |
这个结果说明了两个问题:
- super().foo()调用了父类A的foo方法
- super().foo()调用父类方法时,父类方法中接收到的self对象不是父类实例而是子类的实例
多继承
再定义两个类,看看多继承会有什么不同
1 | class C(A): |
ABCD四个类的继承关系是一个典型的“菱形继承”,如下:
1 | A |
执行以下代码
1 | d = D() |
输出如下
1 | A.foo <__main__.D object at 0x000001DDD2AADB70> |
从结果可以看出,C并不是B的父类,但是B类中的super().foo()却调用了C类的foo方法,这是为什么呢?
在多继承中使用super并不像单继承那么简单,会涉及到方法查找顺序(MRO)。
super如何查找方法
super实质上是一个类,而不是函数或者其他数据结构。
当调用super()的时候,实际上是创建了一个super类的实例。
1 | >>> class A: |
在大多数情况下,super对象包含了两个非常重要的信息,MRO(Method Resolution Order)列表和MRO中的一个类。
- 当使用super(type1, obj)方式调用super时,MRO列表指的是type(obj)的MRO列表,type1是MRO中的一个类,同时要满足isinstance(obj, type1) is True。
- 当使用super(type1, type2)方式调用super时,MRO指的是type2的MRO列表,type1是MRO中的一个类,同时issubclass(type2, type1) is True。
super会从MRO列表中type1之后的类中查找,查找要执行的方法对象后再返回这个对象。
比如说有个MRO列表:
1 | [A, B, C, D, object] |
下面的调用:
1 | super(B, A).foo() |
super只会从B之后查找,即只会在C、D、object中查找foo方法。
多继承中super的工作方式
回到前面的多继承的例子
1 | d = D() |
D的MRO是:[D, B, C, A, object]。(可以通过D.mro()来查看D的MRO信息)
代码分析如下:
1 | class A: |