super() 和 Parent class 名称有什么区别?
What's the difference between super() and Parent class name?
使用super()
和直接使用父class名字有区别吗?例如:
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()
委托给下一个object 在 方法解析顺序 (MRO) 中,如 documentation:
中指定
super([type[, object-or-type]])
Return a proxy object that delegates method calls to a parent or
sibling class of type. This is useful for accessing inherited methods
that have been overridden in a class. The search order is same as that
used by getattr()
except that the type itself is skipped.
The __mro__
attribute of the type lists the method resolution search order used by both getattr()
and super()
. The attribute
is dynamic and can change whenever the inheritance hierarchy is
updated.
(...)
(已复制,已添加粗体)
比如你定义了 classes(借自 ):
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__
;
super().__init__
of D
是 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()
本身并不代表 parent。例如 D
的 super()
是 B
而 B
不是 D
的超级 class,所以它确实是 取决于 object 的类型(而不是 class)。
现在在 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
的上下文中它认为:
super().__init__
of D
是 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)
发现您没有通过 "self" - 它是自动插入的。
super()
最初是在 Python 2 中设计的,以允许 classes 在 class 层次结构中以其直接上级 class 可能会改变:
让我们假设在某个时间点您的代码如下:
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__
:但是当 superclass 名称被硬编码时,不会发生 - A
的 __init__
总是下一个。
如果您在 C
中硬编码 B.__init__
,您将阻止 C
在没有 B
的情况下工作,从而破坏多重继承的目的。
当您改用 super()
时,Python 执行方法搜索下一个父级 class,寻找 class 的 __mro__
属性(mro = 方法解析顺序。__mro__
是附加到每个 Python class 的具体属性)。 - 因此,如果在某个时间点 class D
不再继承自 B
,C
中对 super().__init__
的调用将自动重新路由直接到 A
.
还值得注意的是,在 Python 3 中引入了 super
的无参数形式以方便其使用——在此之前,必须硬编码对自己 class 并在参数中插入 self
。这种形式是 Python 中为数不多的在编译器本身中硬编码的例外之一 - 当在方法主体中看到 super
(或 __class__
)时,它确实会在方法内部更改内容(即,它创建一个 __class__
变量,指向 class 本身,super
调用使用)
使用super()
和直接使用父class名字有区别吗?例如:
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()
委托给下一个object 在 方法解析顺序 (MRO) 中,如 documentation:
super([type[, object-or-type]])
Return a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class. The search order is same as that used by
getattr()
except that the type itself is skipped.The
__mro__
attribute of the type lists the method resolution search order used by bothgetattr()
andsuper()
. The attribute is dynamic and can change whenever the inheritance hierarchy is updated.(...)
(已复制,已添加粗体)
比如你定义了 classes(借自
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__
是D.__init__
;super().__init__
ofD
是B.__init__
;super().__init__
是C.__init__
;super().__init__
是E.__init__
;super().__init__
是G.__init__
;super().__init__
是H.__init__
;super().__init__
是F.__init__
;和super().__init__
是object.__init__
。
A
的 B
的 C
的 E
的 G
的 H
的 F
的 因此请注意,super()
本身并不代表 parent。例如 D
的 super()
是 B
而 B
不是 D
的超级 class,所以它确实是 取决于 object 的类型(而不是 class)。
现在在 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
的上下文中它认为:
super().__init__
ofD
是E.__init__
;super().__init__
是G.__init__
;super().__init__
是H.__init__
;super().__init__
是F.__init__
;和super().__init__
是object.__init__
。
E
的 G
的 H
的 F
的 所以这里 D
的 super()
导致 E
(对于 __init__
) 即 在 A
.
super().__init__(*args, **kwargs)
发现您没有通过 "self" - 它是自动插入的。
super()
最初是在 Python 2 中设计的,以允许 classes 在 class 层次结构中以其直接上级 class 可能会改变:
让我们假设在某个时间点您的代码如下:
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__
:但是当 superclass 名称被硬编码时,不会发生 - A
的 __init__
总是下一个。
如果您在 C
中硬编码 B.__init__
,您将阻止 C
在没有 B
的情况下工作,从而破坏多重继承的目的。
当您改用 super()
时,Python 执行方法搜索下一个父级 class,寻找 class 的 __mro__
属性(mro = 方法解析顺序。__mro__
是附加到每个 Python class 的具体属性)。 - 因此,如果在某个时间点 class D
不再继承自 B
,C
中对 super().__init__
的调用将自动重新路由直接到 A
.
还值得注意的是,在 Python 3 中引入了 super
的无参数形式以方便其使用——在此之前,必须硬编码对自己 class 并在参数中插入 self
。这种形式是 Python 中为数不多的在编译器本身中硬编码的例外之一 - 当在方法主体中看到 super
(或 __class__
)时,它确实会在方法内部更改内容(即,它创建一个 __class__
变量,指向 class 本身,super
调用使用)