2009-04-15 71 views
100

我讀「深入Python」並在班章重寫__init__它給出了這樣的例子:傳承與蟒蛇

class FileInfo(UserDict): 
    "store file metadata" 
    def __init__(self, filename=None): 
     UserDict.__init__(self) 
     self["name"] = filename 

作者接着說,如果你想覆蓋__init__方法,你必須用正確的參數明確地呼叫父母__init__

  1. 如果FileInfo類擁有多個祖先類,該怎麼辦?
    • 我必須顯式調用所有的祖先類__init__方法?
  2. 此外,我必須這樣做,我想重寫任何其他方法?
+3

請注意,重載是一個與重寫相分離的概念。 – 2009-04-15 21:02:00

+2

是,由於固定它 – 2009-04-15 21:05:38

回答

129

這本書對於子類超類調用有點過時。對於子類內置類也有點過時。

現在看起來像這樣。

class FileInfo(dict): 
    """store file metadata""" 
    def __init__(self, filename=None): 
     super(FileInfo, self).__init__() 
     self["name"] = filename 

請注意以下幾點。

  1. 我們可以直接繼承內建類,如dictlisttuple

  2. super函數處理追查這個類的父類和它們適當地調用函數。

+4

我應該找一個更好的書/教程? – 2009-04-15 20:54:41

+1

因此,在多重繼承的情況下,super()是否以您的名義跟蹤它們? – Dana 2009-04-15 20:54:44

+2

dict .__ init __()有什麼問題? – 2009-04-15 21:06:10

3

如果FileInfo類有多個祖先類,那麼你應該明確地調用它們所有的__init __()函數。您也應該對__del __()函數執行相同的操作,這是一個析構函數。

2

是的,你必須調用__init__每個父類。如果您重寫父項中存在的函數,則函數也是如此。

10

你真的不調用基類(ES)的__init__方法,但你通常這樣做,因爲基類會在那裏做一些重要的初始化所需要的休息類方法的工作。

其他方法取決於你的意圖。如果你只是想添加一些基類的行爲,你會想要調用基類的方法另外你自己的代碼。如果你想從根本上改變行爲,你可能不會調用基類的方法,並直接在派生類中實現所有的功能。

+4

有關技術完整性,有的班級,像threading.Thread,會如果你曾經嘗試避免調用父類的__init__拋出巨大的錯誤。 – 2009-04-15 21:39:36

+5

我發現所有這些「你不必調用基地的構造函數」說話非常惱人。你不必用我知道的任何語言來稱呼它。所有這些人都會以同樣的方式搞砸(或不會),不會初始化成員。建議不要初始化基類在很多方面都是錯誤的。如果一個類現在不需要初始化,它將來需要它。構造函數是類結構/語言結構的接口的一部分,應該正確使用。它的正確用法是在派生的構造函數中調用它。這樣做。 – AndreasT 2013-06-05 21:29:04

17

在您需要繼承的每個類中,您可以運行每個需要在啓動子類時初始化的類的循環...可以更好地理解複製的示例...

class Female_Grandparent: 
    def __init__(self): 
     self.grandma_name = 'Grandma' 

class Male_Grandparent: 
    def __init__(self): 
     self.grandpa_name = 'Grandpa' 

class Parent(Female_Grandparent, Male_Grandparent): 
    def __init__(self): 
     Female_Grandparent.__init__(self) 
     Male_Grandparent.__init__(self) 

     self.parent_name = 'Parent Class' 

class Child(Parent): 
    def __init__(self): 
     Parent.__init__(self) 
#---------------------------------------------------------------------------------------# 
     for cls in Parent.__bases__: # This block grabs the classes of the child 
      cls.__init__(self)  # class (which is named 'Parent' in this case), 
            # and iterates through them, initiating each one. 
            # The result is that each parent, of each child, 
            # is automatically handled upon initiation of the 
            # dependent class. WOOT WOOT! :D 
#---------------------------------------------------------------------------------------# 



g = Female_Grandparent() 
print g.grandma_name 

p = Parent() 
print p.grandma_name 

child = Child() 

print child.grandma_name 
+1

似乎不需要'Child .__ init__'中的for循環。當我從例子中刪除它時,我的孩子仍然會打印「奶奶」。是不是由'Parent'類處理的祖父初始化? – Adam 2014-04-30 22:17:52

+2

我認爲granparents的init已經被Parent的init處理過了,不是嗎? – johk95 2014-12-14 16:33:28