2017-05-05 77 views
2

爲什麼我在創建threading.Thread類時被迫使用threading.Thread.__init__(self)super(ClassName, self).__init__()爲什麼需要Thread .__ init __()在Class中?

例如:

class Threader(threading.Thread): 
    def __init__(self, _fp, _q): 
     threading.Thread.__init__(self) 
     self.path = _fp 
     self.queue = _q 

    def run(self): 
     # Do stuff 

class Threader(threading.Thread): 
    def __init__(self, _fp, _q): 
     super(Threader, self).__init__() 
     self.path = _fp 
     self.queue = _q 

    def run(self): 
     # Do stuff 

這兩種方法的工作,並做大致相同的事情。但是,如果我刪除了.__init__()方法,我會收到堆棧:from thread.start(): thread.__init__() not called

不應該定義我自己的def __init__()「替換」.__init__()方法?

我讀過this其他SO帖子,並與我的想法一致,但得到相同的堆棧錯誤。

+1

爲什麼要細化'Thread'類呢?爲什麼不實例化一個'Thread'並給它一個可調用委託? 'my_thread = threading.Thread(target = my_callable)' –

+0

@jameslarge語法對於我們在GUI更新中所做的操作來說更加清晰。 –

回答

3

考慮這個簡單的例子:

class dog: 
    def __init__(self): 
     self.legs = 4 
     self.sound = 'woof' 

class chihuahua(dog): 
    def __init__(self): 
     self.sound = 'yip' 
     # what's missing here? 

我們已經創造的dog一個子類,叫做chihuahua。這個班級的用戶會合理地期望它在所有默認方面都表現得像狗一樣,除了我們已經覆蓋的具體內容(它所產生的聲音)之外。但請注意,正如您所指出的,新子類__init__取代基類__init__完全取代。與C++不同,在創建子類實例時,基類初始化代碼是而不是。因此,創建chihuahua()時,self.legs = 4行永遠不會運行。結果,這種類型的狗跑來跑去,不知道它有多少腿。因此,你可能會認爲它不是一個功能完整的狗,如果它在嘗試執行復雜的技巧時跌倒了,你不應該感到驚訝。

作爲子類設計器,你有兩個選擇來解決這個問題。首先是在子類中顯式重新實現self.legs = 4行。那麼,在這個例子中,這樣做可以很好地工作,但它通常不是一個好的選擇,因爲它違反了DRY原則,即使在你確實知道要寫什麼代碼以及如何維護它的情況下。而在更復雜的例子中(比如你的Thread子類),你大概會知道不會知道。第二種選擇:顯式調用超類初始化器並讓它做它的事情。

1

定義您自己的__init__將覆蓋基類。但是基地__init__所做的所有工作如何使線程可以運行?所有通常會創建的變量和狀態都會丟失。除非你自己破解所有這些(爲什麼這麼做?),這個線程當然是完全無法運行的。

當然,並非所有的課程都需要__init__,但絕大多數課程都需要。即使是那些不這樣做的人,調用__init__也是無害的 - 它只是去object.__init__,並且如果實施者決定__init__畢竟是有用的,那麼將來會對子類進行驗證。

相關問題