[英]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.