cod*_*ash 13 python inheritance initialization super method-resolution-order
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()
Run Code Online (Sandbox Code Playgroud)
是否有内部之间的差异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__()
Run Code Online (Sandbox Code Playgroud)
接着__mro__的A是:
A.__mro__ == (A,D,B,C,E,G,H,F,object)
Run Code Online (Sandbox Code Playgroud)
现在,如果我们打电话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>
Run Code Online (Sandbox Code Playgroud)
所以这意味着在A尝试获取__init__它的上下文中:
super().__init__的A是D.__init__;super().__init__的D是B.__init__;super().__init__的B是C.__init__;super().__init__的C是E.__init__;super().__init__的E是G.__init__;super().__init__的G是H.__init__;super().__init__的H是F.__init__; 和super().__init__的F是object.__init__.因此请注意,super()本身并不代表父母.例如super(),Dis B和Bis不是超类D,所以它实际上取决于对象的类型(不在类上).
现在,如果是D,那__mro__就是:
D.__mro__ = (D,E,G,H,F,object)
Run Code Online (Sandbox Code Playgroud)
如果我们构建一个,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>
Run Code Online (Sandbox Code Playgroud)
所以在D它的背景下认为:
super().__init__的D是E.__init__;super().__init__的E是G.__init__;super().__init__的G是H.__init__;super().__init__的H是F.__init__; 和super().__init__的F是object.__init__.因此,这里的super()的D导致E(对于__init__)这是不是在上下文中的相同A.
super().__init__(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
感觉你没有传递“自我”——它是自动插入的。
super()最初是在 Python 2 中设计的,允许类在类层次结构中作为 mixins 重用,其直接超类可能会发生变化:
假设在某个时间点您的代码如下:
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
Run Code Online (Sandbox Code Playgroud)
此时,应该执行正确的 OOP 代码,C.__init__ 该代码应该将调用链接到B.__init__: 但当超类名称被硬编码时,不会发生 -A总是__init__接下来。如果您B.__init__在 中进行硬编码C,那么您将C无法在没有 的情况下工作B,从而违背了多重继承的目的。
当您使用super()替代方法时,Python 会根据类的属性执行下一个父类的方法搜索__mro__(mro = 方法解析顺序。__mro__是附加到每个 Python 类的具体属性)。- 因此,如果在某个时间点D上面的类不再继承自,则对 inB的调用将自动重新直接路由到。super().__init__CA
还值得注意的是,在 Python 3 中引入了无参数形式super来简化其使用 - 在此之前,必须硬编码对自己的类的引用并插入self参数。这种形式是 Python 中为数不多的在编译器本身中硬编码的例外之一 - 当在方法体中看到super(或) 时,它确实会在方法内部更改内容(即,它创建一个指向调用该类本身的变量)用途)__class____class__super