[英]Does a derived class automatically have all the attributes of the base class?
似乎沒有好的在線文檔:如果我創建一個派生類,它會自動擁有基類的所有屬性嗎? 但是什么是BaseClass.__init()
,你還需要對其他基類方法做嗎? BaseClass.__init__()
是否需要參數? 如果您有基類__init__()
,它們是否也被派生類使用,您是否需要顯式設置派生classe的__init__()
,或者將它們設置為BaseClass.__init__()
?
如果在從BaseClass派生的類中實現__init__
,那么它將覆蓋繼承的__init__
方法,因此永遠不會調用BaseClass.__init__
。 如果你需要為BaseClass調用__init__
方法(通常就是這種情況),那么由你來做,並通過調用BaseClass.__init__
顯式完成,通常來自新實現的__init__
方法。
class Foo(object):
def __init__(self):
self.a = 10
def do_something(self):
print self.a
class Bar(Foo):
def __init__(self):
self.b = 20
bar = Bar()
bar.do_something()
這將導致以下錯誤:
AttributeError: 'Bar' object has no attribute 'a'
因此, do_something
方法已按預期繼承,但該方法需要設置屬性a
,它永遠不會因為__init__
也被覆蓋。 我們通過在Bar.__init__
明確調用Foo.__init__
來解決Bar.__init__
。
class Foo(object):
def __init__(self):
self.a = 10
def do_something(self):
print self.a
class Bar(Foo):
def __init__(self):
Foo.__init__(self)
self.b = 20
bar = Bar()
bar.do_something()
按預期打印10
張。 在這種情況下, Foo.__init__
需要一個參數,它是Foo
一個實例(按照慣例,它被稱為self
)。
通常,當您在類的實例上調用方法時,類實例將作為第一個參數自動傳遞。 類實例上的方法稱為綁定方法 。 bar.do_something
是綁定方法的一個示例(您將注意到它在沒有任何參數的情況下被調用)。 Foo.__init__
是一個未綁定的方法,因為它沒有附加到Foo
的特定實例,因此需要顯式傳遞第一個參數,即Foo
的實例。
在我們的例子中,我們將self
傳遞給Foo.__init__
,這是傳遞給Bar
中的__init__
方法的Bar
的實例。 由於Bar
繼承自Foo
, Bar
的實例也是Foo
實例,因此允許將self
傳遞給Foo.__init__
。
很可能是您繼承的類需要或接受的參數多於該類的實例。 這些處理方式與您在__init__
調用的任何方法一樣處理:
class Foo(object):
def __init__(self, a=10):
self.a = a
def do_something(self):
print self.a
class Bar(Foo):
def __init__(self):
Foo.__init__(self, 20)
bar = Bar()
bar.do_something()
哪個會打印20
。
如果您嘗試通過繼承類實現完全公開基類的所有初始化參數的接口,則需要明確地這樣做。 這通常使用* args和** kwargs參數(名稱按慣例)來完成,這些參數是未明確命名的所有其余參數的占位符。 以下示例使用了我討論過的所有內容:
class Foo(object):
def __init__(self, a, b=10):
self.num = a * b
def do_something(self):
print self.num
class Bar(Foo):
def __init__(self, c=20, *args, **kwargs):
Foo.__init__(self, *args, **kwargs)
self.c = c
def do_something(self):
Foo.do_something(self)
print self.c
bar = Bar(40, a=15)
bar.do_something()
在這種情況下,參數c
設置為40,因為它是Bar.__init__
的第一個參數。 然后將第二個參數合並到變量args
和kwargs
(*和**是特定的語法,表示在傳遞給函數/方法時將列表/元組或字典擴展為單獨的參數),並傳遞給Foo.__init__
。
此示例還指出,如果需要,則需要顯式調用任何重寫方法(在本例中為do_something
)。
最后一點,您將經常看到super(ChildClass, self).method()
(其中ChildClass
是一些任意子類),而不是顯式調用BaseClass
方法。 關於super
討論是另一個問題,但足以說明,在這些情況下,它通常被用來通過調用BaseClass.method(self)
完成正在做的事情。 簡而言之, super
將方法調用方法調用到方法解析順序中的下一個類--MRO(在單繼承中是父類)。 有關詳細信息,請參閱super上的文檔 。
如果我創建一個派生類,它會自動擁有基類的所有屬性嗎?
類屬性,是的。 實例屬性,否(僅僅因為它們在創建類時不存在),除非派生類中沒有__init__
,在這種情況下將調用基本類,並將設置實例屬性。
是BaseClass。 init ()需要參數嗎?
取決於班級及其__init__
簽名。 如果您在派生類中顯式調用Base.__init__
,則至少需要將self
作為第一個參數傳遞。 如果你有
class Base(object):
def __init__(self):
# something
那么很明顯__init__
沒有接受其他論點。 如果你有
class Base(object):
def __init__(self, argument):
# something
那么你在調用base __init__
時必須傳遞argument
。 這里沒有火箭科學。
如果您的基類init ()有參數,它們是否也被派生類使用,您是否需要顯式設置派生classe的init ()的參數,或者將它們設置為BaseClass。 init ()而不是?
同樣,如果派生類沒有__init__
,則將使用基礎類。
class Base(object):
def __init__(self, foo):
print 'Base'
class Derived(Base):
pass
Derived() # TypeError
Derived(42) # prints Base
在其他情況下,你需要以某種方式照顧它。 你是否使用*args, **kwargs
並且只是將未修改的參數傳遞給基類,或者復制基類簽名,或者從其他地方提供參數,取決於你想要完成的任務。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.