2016-09-28 30 views
1

我在Python中有一個簡單的mixin結構。代碼應該是自我解釋:如何改進Python中的mixin結構?

class Base: 
    def __init__(self): 
     pass 

class MixinA: 
    def __init__(self): 
     self.x = 0 
     self.y = 1 
    def a(self): 
     print('A: x = ' + str(self.x) + ', y = ' + str(self.y)) 

class MixinB: 
    def __init__(self): 
     self.x = 2 
     self.z = 3 
    def b(self): 
     print('B: x = ' + str(self.x) + ', z = ' + str(self.z)) 

class MyFirstMix(MixinA, MixinB, Base): 
    def __init__(self): 
     Base.__init__(self) 
     MixinB.__init__(self) 
     MixinA.__init__(self) 

class MySecondMix(MixinA, Base): 
    def __init__(self): 
     Base.__init__(self) 
     MixinA.__init__(self) 

我想改善這一點,所以這導致了3個問題/問題:

  1. MixinAMixinB都有一個成員x。有沒有辦法確定,每個班級只能看到自己的x據我所知:不,不是。
  2. 爲混合類中的每個mixin調用構造函數有點麻煩。有沒有辦法自動調用所有的構造函數或做一些具有相同效果的東西?
  3. 有沒有一種方法可以動態地混入一些內聯的東西,而不需要明確地創建一個類?我正在尋找一個語法,如:mix = Base() with MixinA

如果我的建議結構是完全錯誤的,我也打開其他建議如何處理mixin。

+0

[在Python中阻止函數重寫](http://stackoverflow.com/questions/3948873/prevent-function-overriding-in-python)可能的重複。您可以使用此處提及的類似技術來防止重寫實例屬性。 –

+0

@NoctisSkytower:那麼,問題2和3的含義是什麼? – Michael

+0

那些可能並可能應該作爲單獨的問題發佈。 –

回答

0

當您的繼承方案開始受到這些問題的困擾時,應該考慮使用名爲組合的技術來代替。關於主題here的可讀介紹。 Wikipedia example的可訪問性稍差,但如果可以處理其他編程語言,也很有用。 This StackExchange question也提供有用的討論。

在最簡單的,而不是一類從SomeParent繼承和在Mixin類混合,你不是有SomeParent實例各創建Mixin一個實例,並用它來訪問mixin類的功能。

0

對於Python類固有的,我相信有一些你需要知道的技巧:

  1. 類在python2和python3有很大的不同。 Python2支持舊式類,但python3僅支持新式類。簡單地說:在python3中,即使你沒有明確地使用它,類也總是固有於基類object。檢查Difference-between-Old-New-Class

  2. 方法解析順序(MRO)。這決定派生類如何搜索固有成員和函數。見MRO

  3. super功能。結合MRO,您可以輕鬆調用父成員或函數,而無需明確知道父類的名稱。見Super

現在來找你的問題:

  1. MixinA和MixinB都有一個成員x。有沒有辦法確定,每個班級只能看到自己的x?

我不放棄理解你的意思。當你引用一個類的成員時,你必須通過它的實例或類來引用它。所以instance_of_MixinA.xinstance_of_MixinB.x是分開的。如果你正在談論類MyFirstMix(MixinA, MixinB, Base),這取決於如何調用__init__函數。在您的代碼中,您首先通過MixinB填充x,然後將其值重置爲MixinA

  1. 調用混合類中每個mixin的構造函數有點麻煩。有沒有辦法自動調用所有的構造函數或做一些具有相同效果的東西。

您的稱謂使它不可能。你必須調用所有的構造函數。

  1. 有沒有一種方法可以動態混入一些內聯的東西,而不需要顯式地創建一個類?

我不確定。但我可以給你一些建議:儘量外__init__成員時,高清類(python3,如果使用python2照顧super):

class Base: 
    def __init__(self): 
     pass 


class MixinA: 
    x = 0 
    y = 1 


class MixinB: 
    x = 2 
    z = 3 

    def b(self): 
     print('B: x = ' + str(self.x) + ', z = ' + str(self.z)) 


class MyFirstMix(MixinA, MixinB, Base): 
    def __init__(self): 
     super().__init__() 


class MySecondMix(MixinA, Base): 
    def __init__(self): 
     super().__init__() 

__init__的行爲變量,從內部變量退出不同:外變量屬於類,並且將爲此類的所有實例填充,而內部變量僅屬於實例(在定義類時由self引用),並且只有在調用__init__時纔會填充。這就是爲什麼你不能使用super來調用所有的構造函數--- super只能稱爲優先級父項__init__。見variables-outsite-inside-init

這是一個很好的解決Mixin類。在以上代碼中,MyFirstMix內部人員MixinAMixinB其成員均爲班級成員(__init__以外)。因此MyFirstMix的實例將固有所有類別成員MixinAMixinB而不呼叫__init__。這裏的MixinAMixinB自己的同類成員x,但MRO確定當MyFirstMix的實例參考x,應該從MixinA返回。

希望這會有所幫助。謝謝!