2009-09-15 31 views
6

我見過關於此主題的幾個問題,但我一直未能找到明確的答案。如何混合舊式和新式Python類?

我想知道在新的Python代碼庫中使用舊式類的正確方法。比方說,我有兩個固定類別,AB。如果我要繼承一個,並轉換爲新的樣式類(A2B2),這個工程。但是,如果我想創建一個新類別C,從A2B2有一個問題。

因此,如果任何基類被定義爲舊式,那麼是否有可能繼續使用此方法,或者是否所有類都必須符合舊式?

見澄清示例代碼:

class A: 
    def __init__(self): 
     print 'class A' 

class B: 
    def __init__(self): 
     print 'class B' 

class A2(A,object): 
    def __init__(self): 
     super(A2, self).__init__() 
     print 'class A2' 

class B2(B,object): 
    def __init__(self): 
     super(B2, self).__init__() 
     print 'class B2' 

class C(A2, B2): 
    def __init__(self): 
     super(C,self).__init__() 
     print 'class C' 

A2() 
print '---' 
B2() 
print '---' 
C() 

這段代碼的輸出:

class A 
class A2 
--- 
class B 
class B2 
--- 
class A 
class A2 
class C 

正如你所看到的,問題是,在調用C(),類B2從未初始化。


更新 - 新型類的實例

我想這是不明確的使用super當正確的初始化序列應該是什麼。這是一個工作示例,其中調用超級確實初始化所有基類,而不僅僅是第一個它找到的

class A(object): 
    def __init__(self): 
     super(A, self).__init__() 
     print 'class A' 

class B(object): 
    def __init__(self): 
     super(B, self).__init__() 
     print 'class B' 

class A2(A): 
    def __init__(self): 
     super(A2, self).__init__() 
     print 'class A2' 

class B2(B): 
    def __init__(self): 
     super(B2, self).__init__() 
     print 'class B2' 

class C(A2, B2): 
    def __init__(self): 
     super(C, self).__init__() 
     print 'class C' 

C() 

,併產生輸出:

class B 
class B2 
class A 
class A2 
class C 
+0

已更新的答案包括鑽石繼承的解釋和新風格類解決的問題。 – 2009-09-15 10:40:54

+0

爲什麼你甚至有老式的課程呢? – 2009-09-15 10:52:39

+0

第三方模塊,也許? – 2009-09-15 13:23:50

回答

6

這不是新老樣式類混合的問題。 super()不會調用全部的基類函數,它會根據方法解析順序調用它找到的第一個函數。在這種情況下A2,這反過來如果你想調用兩次調用A.

,明確地這樣做:

class C(A2, B2): 
    def __init__(self): 
     A2.__init__(self) 
     B2.__init__(self) 
     print 'class C' 

這應該解決這個問題。

更新:

的菱形繼承問題,因爲你指的是在一個鑽石繼承情況調用哪一個類,像這樣的問題:

class A: 
    def method1(self): 
     print 'class A' 

    def method2(self): 
     print 'class A' 

class B(A): 
    def method1(self): 
     print 'class B' 

class C(A): 
    def method1(self): 
     print 'class C' 

    def method2(self): 
     print 'class C' 

class D(B, C): 
    pass 

現在測試了這一點:

>>> D().method1() 
'class B' 

這是正確的。它稱第一類的實施。 然而,讓我們試試這個方法二用:

>>> D().method2() 
'class A' 

Oups,錯!它應該在這裏調用類C.method2(),因爲即使類B不覆蓋method2,類C也是如此。現在,讓A類一類newstyle:

class A(object): 
    def method1(self): 
     print 'class A' 

,然後再試一次:

>>> D().method1() 
'class B' 
>>> D().method2() 
'class C' 

和變戲法似的,它的工作原理。這是新舊風格類之間的方法解析順序差異,這有時會讓混淆它們變得混亂。

請注意,B和C都不會被調用。即使我們稱之爲超級,情況也是如此。

class D(B, C): 
    def method1(self): 
     super(D, self).method1() 

    def method2(self): 
     super(D, self).method2() 

>>> D().method1() 
'class B' 
>>> D().method2() 
'class C' 

如果你想同時調用B和C,你必須明確地調用它們。

現在,如果你別讓鑽石,就像在你例如,具有單獨的基類,結果是不同的:

class A1(object): 
    def method1(self): 
     print 'class A1' 

    def method2(self): 
     print 'class A1' 

class A2(object): 
    def method1(self): 
     print 'class A2' 

    def method2(self): 
     print 'class A2' 

class B(A1): 
    def method1(self): 
     print 'class B' 

class C(A2): 
    def method1(self): 
     print 'class C' 

    def method2(self): 
     print 'class C' 

class D(B, C): 
    def method1(self): 
     super(D, self).method1() 

    def method2(self): 
     super(D, self).method2() 


>>> D().method1() 
'class B' 
>>> D().method2() 
'class A1' 

這也是每設計。仍然沒有兩個基類被調用。如果你想要發生這種情況,你仍然需要明確地調用它們。

+0

Super會調用所有基類方法,如果使用所有新樣式類實現並且一致使用。我的問題是當你被迫混入一箇舊式課堂時,如何處理這個案例。我知道如何直接調用父方法,但是這會打破鑽石繼承。 – cmcginty 2009-09-15 09:18:33

+0

不,它不會。如果您製作A和B的新式課程,您會得到與上述完全相同的結果。我不明白它如何打破鑽石繼承,直接調用父方法。我懷疑你的鑽石繼承問題稍微倒退了。事實上,你似乎認爲菱形繼承應該調用兩個基類(它通常不會),而在Python中這樣做的唯一方法就是明確地調用它們。 – 2009-09-15 10:05:13

+0

查看我的更新,超執行所有\ __ init \ __方法。 – cmcginty 2009-09-15 19:27:52