使用super()
和直接使用父类名有区别吗?例如:
class Parent:
def __init__(self):
print("In parent")
self.__a=10
class Child(Parent):
def __init__(self):
super().__init__() # using super()
Parent.__init__(self) # using Parent class name
c=Child()
super().__init__()
和Parent.__init__(self)
之间有内部差异吗?
不是在这种情况下。但通常,尤其是在使用多重继承时,按照文档中的规定,super()
委托给方法解析顺序 (MRO)中的下一个对象:
super([type[, object-or-type]])
返回将方法调用委托给父对象或 类型的同级类。这对于访问继承的方法很有用 在类中已被覆盖。搜索顺序与此相同 由
getattr()
使用,但跳过类型本身除外。类型的
__mro__
属性列出了getattr()
和super()
使用的方法解析搜索顺序。属性 是动态的,只要继承层次结构 更新。(...
(复制,粗体添加)
例如,假设您定义了这样的类(借用了这个问题,其中更详细地讨论了 MRO):
class F:
def __init__(self):
print('F%s'%super().__init__)
super().__init__()
class G:
def __init__(self):
print('G%s'%super().__init__)
super().__init__()
class H:
def __init__(self):
print('H%s'%super().__init__)
super().__init__()
class E(G,H):
def __init__(self):
print('E%s'%super().__init__)
super().__init__()
class D(E,F):
def __init__(self):
print('D%s'%super().__init__)
super().__init__()
class C(E,G):
def __init__(self):
print('C%s'%super().__init__)
super().__init__()
class B(C,H):
def __init__(self):
print('B%s'%super().__init__)
super().__init__()
class A(D,B,E):
def __init__(self):
print('A%s'%super().__init__)
super().__init__()
那么A
的__mro__
是:
A.__mro__ == (A,D,B,C,E,G,H,F,object)
现在如果我们调用A()
,它会打印:
A<bound method D.__init__ of <__main__.A object at 0x7efefd8645c0>>
D<bound method B.__init__ of <__main__.A object at 0x7efefd8645c0>>
B<bound method C.__init__ of <__main__.A object at 0x7efefd8645c0>>
C<bound method E.__init__ of <__main__.A object at 0x7efefd8645c0>>
E<bound method G.__init__ of <__main__.A object at 0x7efefd8645c0>>
G<bound method H.__init__ of <__main__.A object at 0x7efefd8645c0>>
H<bound method F.__init__ of <__main__.A object at 0x7efefd8645c0>>
F<method-wrapper '__init__' of A object at 0x7efefd8645c0>
<__main__.A object at 0x7efefd8645c0>
因此,这意味着在A
的背景下以及尝试获得__init__
时:
A
的super().__init__
是D.__init__
;D
的super().__init__
是B.__init__
;B
super().__init__
是C.__init__
;C
super().__init__
是E.__init__
;E
的super().__init__
是G.__init__
;G
super().__init__
是H.__init__
;H
的super().__init__
是F.__init__
;和F
super().__init__
是object.__init__
.
因此请注意,super()
本身并不委托给父级。例如,D
的super()
是B
的,而B
不是D
的超类,所以它实际上取决于对象的类型(而不是类)。
现在在D
的情况下,__mro__
是:
D.__mro__ = (D,E,G,H,F,object)
如果我们构造一个D
但是我们会得到:
D<bound method E.__init__ of <__main__.D object at 0x7efefd864630>>
E<bound method G.__init__ of <__main__.D object at 0x7efefd864630>>
G<bound method H.__init__ of <__main__.D object at 0x7efefd864630>>
H<bound method F.__init__ of <__main__.D object at 0x7efefd864630>>
F<method-wrapper '__init__' of D object at 0x7efefd864630>
因此,在D
的背景下,它认为:
D
super().__init__
是E.__init__
;E
的super().__init__
是G.__init__
;G
super().__init__
是H.__init__
;H
super().__init__
是F.__init__
;和F
super().__init__
是object.__init__
.
所以这里D
的super()
导致E
(对于__init__
),这在A
的上下文中是不一样的。
super().__init__(*args, **kwargs)
感知你没有传递"自我"——它是自动插入的。
super()
最初是在Python 2中设计的,允许类作为类层次结构中的mixin重用,其直接超类可能会改变:
让我们在某个时间点支持您的代码是这样的:
class A: pass
class B(A):
def __init__(self, *args, **kwargs):
...
# Fixed call to A
A.__init__(self, *args, **kwargs)
class C(A):
def __init__(self, *args, **kwargs):
...
# Fixed call to A
A.__init__(self, *args, **kwargs)
class D(C, B):
pass
此时,正确的OOP代码应该执行C.__init__
,这将调用链接到B.__init__
:但是当超类名被硬编码时,这不会发生 -A
的__init__
总是下一个。 如果你用C
对B.__init__
进行硬编码,你会阻止C
在没有B
的情况下工作,从而破坏多重继承的目的。
当你改用super()
时,Python 会根据类的__mro__
属性(mro = 方法解析顺序。__mro__
是附加到每个 Python 类的具体属性)。 - 因此,如果在某个时间点,上面的类D
不再继承B
,则对super().__init__
的调用将直接C
自动重新路由到A
。
还值得注意的是,在 Python 3 中引入了无参数形式的super
以方便其使用 - 在此之前,必须对自己的类进行硬编码引用,并在参数中插入self
。这种形式是 Python 中为数不多的在编译器本身中硬编码的例外之一 - 当在方法主体中看到super
(或__class__
)时,它确实会在方法内部更改内容(即,它创建一个指向super
调用使用的类本身的__class__
变量)