[英]What's the difference between super() and Parent class name?
使用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__
:
super().__init__
的A
是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
的上下文中是不一样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
情况下工作,从而B.__init__
多重继承的目的。
当您使用super()
,Python会执行方法搜索下一个查看类的__mro__
属性的子类(mro =方法解析顺序__mro__
是附加到每个Python类的具体属性)。 - 因此,如果在某个时间点上面的D
类不再继承自B
,则对C
super().__init__
的调用将自动重新路由到A
值得注意的是,在Python 3中引入了无参数形式的super
以简化其使用 - 在此之前,必须对自己的类进行硬编码并在参数中插入self
。 这个表单是Python中为数不多的在编译器本身中进行硬编码的例外之一 - 当在方法体内看到super
(或__class__
)时,它会在方法内部进行更改(即,它创建一个指向类本身的__class__
变量) super
电话使用的)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.