python中通过super()调用父类构造方法

可能是java写多了,当我准备通过super(self,xxx)这样调用父类的构造方法时候,一直报错,上网查资料,发现python的super()的机制和java还是有很大区别的。

首先看一下super()函数的定义

super([type[,object-or-type]])

Return a **proxy object**that delegates method calls to a **parent or sibling** class of type

返回一个代理对象,这个对象负责将方法调用分配给第一个参数的一个父类或者同辈的类去完成

理解一下 parent or sibling class:

第一个参数的__mro__属性决定了搜索的顺序, super指的的是 MRO(Method Resolution Order) 中的下一个类, 而不一定是父类!

super()和getattr() 都使用__mro__属性来解析搜索顺序, __mro__实际上是一个只读的元组.

MRO中类的顺序是怎么排的呢?

实际上MRO列表本身是根据一种C3的线性化处理技术确定的, 理论说明可以参考这里, 这里只简单说明一下原则:

在MRO中, 基类永远出现在派生类的后面, 如果有多个基类, 基类的相对顺序不变.

MRO实际上是对继承树做层序遍历的结果, 把一棵带有结构的树变成了一个线性的表, 所以沿着这个列表一直往上, 就可以无重复的遍历完整棵树, 也就解决了多继承中的Diamond问题.

比如说:

class Root:
  pass


class A(Root):
  pass
 
class B(Root):
  pass
 
class C(A, B):
  pass
 
print(C.__mro__)
 
# 输出结果为:
# (, , , , )

super()实际返回的是一个代理的super对象!

调用super()这个构造方法时, 只是返回一个super()对象, 并不做其他的操作.

然后对这个super对象进行方法调用时, 发生的事情如下:

找到第一个参数的__mro__列表中的下一个直接定义了该方法的类, 并实例化出一个对象
然后将这个对象的self变量绑定到第二个参数上, 返回这个对象

比如:

class Root:
  def __init__(self):
    print('Root')
 
class A(Root):
  def __init__(self):
    super().__init__() # 等同于super(A, self).__init__()

在A的构造方法中, 先调用super()得到一个super对象, 然后向这个对象调用init方法, 这是super对象会搜索A的__mro__列表, 找到第一个定义了__init__方法的类, 于是就找到了Root, 然后调用Root.__init__(self), 这里的self是super()的第二个参数, 是编译器自动填充的, 也就是A的__init__的第一个参数, 这样就完成对__init__方法调用的分配.


你可能感兴趣的:(python中通过super()调用父类构造方法)