2016-07-04 74 views
0

我有一種情況,基類方法(Python中的__init__方法)做了很多工作。派生類覆蓋__init__以簡單地設置對象變量,然後委託給基類__init__。這工作正常,但現在我有一種情況。所有派生類都使用的基類方法除了一個

我有一些代碼,非常適合在基類__init__,所有其他派生類除了一個(稱之爲A)需要使用。想象一下,如果基類__init__是這樣的。

def __init__(self): 
    Action 1... 
    Action 2... 

現在,所有的派生類直接委託給這個。但是,A應該只有行動2在其__init__。現在這個觀點很難看。我可以將Action 1和Action 2分成兩個獨立的函數,並讓基類簡單地調用Action2。然後大多數類會有他們的init這樣的東西。

def __init__(self): 
    self.Action1() 
    Other init code... 
    super().__init__() 

A類,這將是

def __init__(self): 
    Some init code.... 
    super().__init__() 

但是你可以看到,有一段代碼(調用self.Action1說)我在最派生類的重複。這不好。我不確定如何用最少的重複代碼優雅地編寫代碼,並且需要一些關於如何去做的建議。

+1

典型的回答是_maybe A不是一個子類really_。考慮把A作爲父類(在層次結構中更高,而不是更低) – Aganju

+0

在調用super()函數後''''''''''''你可以*撤銷*''' )'''? – wwii

+0

@Aganju A是一個孩子。基類包含很多通用代碼。子類實現了一些方法,使它們適合更大的框架。 –

回答

3

最明顯的解決辦法是使用默認參數:類

class Base: 
    def __init__(self, *, doAction1=True): 
     if doAction1: 
      Action 1... 
     Action 2... 

然後A你可以有:

def __init__(self): 
    Some init code.... 
    super().__init__(doAction1=False) 
+0

這看起來不錯。我做了類似的事情,但不是參數,而是設置了基類所依賴的對象屬性。 –

+0

除非另有建議,我接受這個答案。它看起來是最簡單的做法。 –

0

類的屬性,可以被覆蓋 - 類似默認參數在__init__ 。 (Python v2.7類定義)。

class Foo(object): 
    action1 = True 
    action2 = True 
    def __init__(self): 
     if self.action1: 
     print('action1') 
     if self.action2: 
     print('action2') 

class Bar(Foo): 
    def __init__(self): 
     super(Bar, self).__init__() 
     print('Bar') 

class Baz(Foo): 
    action2 = False 
    def __init__(self): 
     super(Baz, self).__init__() 
     print('Baz') 
+0

這可行,但我認爲@ ecatmur的解決方案更清潔。 –

+0

@NoufalIbrahim ...我upvoted ecatmur的解決方案,然後決定發佈此*對比*。 – wwii

0

在做出設計決策時,往往值得考慮繼承是否是正確的選擇。仔細想想你是否真的需要繼承,或者它是否會讓事情變得複雜。

如果您決定實際上並不需要繼承(您正在詢問的當前問題可能會 - 也可能不是 - 這表明是這種情況),在訴諸繼承之前,我建議您探索解決您的問題使用這樣的事情:

def Action1(obj): 
    <do Action 1> 

def Action2(obj): 
    <do Action 2> 

def Action1and2(obj): 
    Action1(obj) 
    Action2(obj) 

class A: 
    def __init__(self): 
     Action2(self) 

class Other: 
    def __init__(self): 
     Action1and2(self) 

注意,對於Other對象,你仍然只有1行代碼,而你完全避免繼承。

如果您決定需要繼承 - 也就是說,您創建的父對象不僅僅是通過某些操作(它們提供附加功能或訪問數據)進行設置 - 您可以嘗試解決您的問題使用組合物代替,如下所示:

class Action1Doer: 
    def __init__(self,obj): 
     <do Action 1> 

class Action2Doer: 
    def __init__(self,obj): 
     <do Action 2> 

class Action1and2Doer: 
    def __init__(self,obj): 
     self.a1 = Action1Doer(obj) 
     self.a2 = Action2Doer(obj) 

class A: 
    def __init__(self): 
     self.thing2 = Action2Doer(self) 

class Other: 
    def __init__(self): 
     self.thing1and2 = Action1and2Doer(self) 

請注意,同樣,每個初始化方法中只有一行代碼。順便說一下,在編碼世界中以這種方式去做事iscertainlynothingnew

你也可以的東西混合在一起:

def Action1(obj): 
    <do Action 1> 

class Action2Doer: 
    def __init__(self,obj): 
     <do Action 2> 

class Action1and2Doer: 
    def __init__(self,obj): 
     Action1(obj) 
     self.a2 = Action2Doer(obj) 

class A: 
    def __init__(self): 
     self.thing2 = Action2Doer(self) 

class Other: 
    def __init__(self): 
     self.thing2 = Action1and2Doer(self).a2 
+0

我想這是可能的,但「Action1and2Doer」聽起來頗爲人爲。沒有? –

+0

這基本上就是你已經使用的基類,對吧?我只是給它一個描述性的名字來解釋清楚。 –