2016-03-08 28 views
0

無處不看我每個人都在說super()是多麼偉大。但是,我傾向於不使用super(),因爲它使得一切都比我想象的複雜得多。我已經看到了一些使用super()的流行示例,但它們似乎從來沒有向基類構造函數中顯示傳遞位置所需的參數。使用超級vs靜態的Python調用基類

我知道Python中的菱形問題,而super()會阻止兩次調用base_base類。 (在這種情況下爲A類)

A類的構造函數被調用兩次這麼糟糕嗎? (即情況2)

下面是我對這兩種情況的代碼。

案例1:使用超()._ 初始化 _()

#abstractclass 
class A(object): 

    #abstractmethod 
    def __init__(self, for_a, *args): 
     self.val_a = for_a 

#abstractclass 
class B(A): 

    #abstractmethod 
    def __init__(self, for_a, for_b, for_c): 
     super().__init__(for_a, for_c) 
     self.val_b = for_b 

#abstractclass 
class C(A): 

    #abstractmethod 
    def __init__(self, for_a, for_c): 
     super().__init__(for_a) 
     self.val_c = for_c 

class D(B, C): 

    def __init__(self, for_a, for_b, for_c, for_d): 
     super().__init__(for_a, for_b, for_c) 
     self.val_d = for_d 

class E(B): 

    def __init__(self, for_a, for_b, for_e, *args): 
     super().__init__(for_a, for_b, *args) 
     self.val_e = for_e 

newobject1 = D(1, 2, 3, 4) 

newobject2 = E(10, 11, 12, 0) 

案例2:靜態 - 使用base._ 初始化 _(個體經營)

#abstractclass 
class A(object): 

    #abstractmethod 
    def __init__(self, for_a): 
     self.val_a = for_a 

#abstractclass 
class B(A): 

    #abstractmethod 
    def __init__(self, for_a, for_b): 
     A.__init__(self, for_a) 
     self.val_b = for_b 

#abstractclass 
class C(A): 

    #abstractmethod 
    def __init__(self, for_a, for_c): 
     A.__init__(self, for_a) 
     self.val_c = for_c 

class D(B, C): 

    def __init__(self, for_a, for_b, for_c, for_d): 
     B.__init__(self, for_a, for_b) 
     C.__init__(self, for_a, for_c) 
     self.val_d = for_d 

class E(B): 

    def __init__(self, for_a, for_b, for_e): 
     super().__init__(for_a, for_b) 
     self.val_e = for_e 

newobject1 = D(1, 2, 3, 4) 

newobject2 = E(10, 11, 12) 
+1

然而'super'並不是對父類的基類的靜態調用的簡單替換。我會建議閱讀[超級考慮超級](https://rhettinger.wordpress.com/2011/05/26/super-considered-super/)和[Python的超級漂亮,但你不能使用它]( https://fuhm.net/super-harmful/)以獲得正確使用它的良好感覺。 – chepner

回答

0

A類的構造函數被調用兩次是否如此糟糕?

當然,如果構造函數很慢,或者它是非冪等的,或者它獲取資源如文件句柄或數據庫連接。在一個更復雜的繼承結構中,你可能也會得到4次或6次構造函數,或者是從子代到祖先的繼承圖的路徑。

我傾向於,因爲它使得一切更加複雜不使用超()比我想的

這不是super使事情複雜化 - 這是多重繼承。在多重繼承中避免使用super只會給您帶來與super的問題不同的,可能更糟糕的問題。

我見過一些流行的使用super()的例子,但他們似乎從來沒有向基類構造函數顯示傳遞位置所需的參數。

這是因爲位置構造函數參數不適用於多重繼承。如果你想使用這樣的多重繼承結構,請嘗試使參數僅爲關鍵字,並使用**kwargs來傳遞其他類要處理的無法識別的參數。 "Python's super() considered super"對如何使其工作有一些很好的建議。

+0

感謝您的反饋!我研究瞭如何使用** kwargs,我認爲它們可能完全符合我的用例。 – btgorman

3

想法是super()是否支持method resolution order,以便您可以使用cooperative inheritance編寫程序。

如果你想調用你的超類的方法,但是你不知道具體是什麼超類,那麼合作繼承是有意義的 - 你只能假設該方法和你寫的方法具有相同的簽名。

在你的例子中,每個__init__是不同的,所以這不是一個很好的協作繼承用例。每個班級實際上都需要知道super的目標,才能正確調用。因此,您在這裏從super得到的好處並不多。


我們不要忘記:多重繼承是混亂的祕訣。有一些慣例(限制條件)可以遵守,以使代碼易於理解並使意大利麪條得到控制。一個想法是使用一些基類作爲mixin。另一個想法是合作繼承。 Python有像super這樣的語言結構來支持這些,但是如果你可以自由地走出這些界限。這有自己的一套問題。