2009-11-11 44 views
12

我是一個對象的子類,以覆蓋我想要添加某些功能的方法。我不想完全替換它,或者添加一個不同名稱的方法,但只需向該方法添加可選參數即可與超類方法兼容。 是否可以使用*args**kwargs來傳遞超類的所有參數,並仍然使用默認值添加可選參數? 我直覺想出了下面的,但它不工作:將一個關鍵字參數添加到重寫的方法並使用** kwarg

class A(object): 
    def foo(self, arg1, arg2, argopt1="bar"): 
     print arg1, arg2, argopt1 

class B(A): 
    def foo(self, *args, argopt2="foo", **kwargs): 
     print argopt2 
     A.foo(self, *args, **kwargs) 


b = B() 
b.foo("a", "b", argopt2="foo") 

當然,我可以得到它的工作時,我明確添加父類的方法的所有參數:

class B(A): 
    def foo(self, arg1, arg2, argopt1="foo", argopt2="bar"): 
     print argopt2 
     A.foo(self, arg1, arg2, argopt1=argopt1) 

這樣做的正確方法是什麼?我必須知道並明確聲明所有重寫的方法參數嗎?

回答

10
class A(object): 
    def foo(self, arg1, arg2, argopt1="bar"): 
     print arg1, arg2, argopt1 

class B(A): 
    def foo(self, *args, **kwargs): 
     argopt2 = kwargs.get('argopt2', default_for_argopt2) 
     # remove the extra arg so the base class doesn't complain. 
     del kwargs['argopt2'] 
     print argopt2 
     A.foo(self, *args, **kwargs) 


b = B() 
b.foo("a", "b", argopt2="foo") 
+5

您可以使用彈出而不是GET + DEL。 – iny 2009-11-11 15:27:05

+0

我總是忘記dict.pop! – 2009-11-11 15:37:31

+3

當'argopt2'未傳遞時,您的示例失敗並出現'KeyError'。使用'kwargs.pop('argopt2',default_for_argopt2)'是修復它的最簡單方法。 – 2009-11-11 17:26:10

1

當繼承和壓倒一切的方法,一個必須決定是否使用super()是一個好主意,this page是好了點。

super()應儘量避免,如文章作者可能是:我是說,super()有必須遵循的一些非常重要的prerequisits如果你不想super()回來咬你。

+0

http://fuhm.org/super-harmful/是一個很好的閱讀。謝謝泰迪 – unutbu 2009-11-11 19:07:17

6

怎樣做的正確方法,我 必須知道並明確聲明的重寫方法的參數都 ?

如果要覆蓋所有的情況下(而不是僅僅依賴於呼叫者經常做的事情你的方式,例如,總是叫你只能用名通過了額外的參數,從不按位置)你必須以編碼(或動態發現)許多有關您所覆蓋的方法簽名的知識 - 這並不奇怪:繼承是一種強大的耦合形式,而重載方法是耦合呈現的一種方式。

可以動態發現超類的通過inspect.getargspec方法的參數,以確保你正確地調用它......但如果類試圖做同樣的事情自省技術可能很麻煩(一旦你知道你的超類的方法接受了*a和/或**kw,你可以做的不過是向上傳遞所有相關的參數,並希望在調用一個不太容忍的版本之前,上游方法鏈最終進行適當的清理, 。

當你設計一個包裝器時,這樣的價格可能是值得的,這個包裝器應該被動態地應用於各種各樣的簽名(特別是因爲在一個裝飾器設置中你可以安排一次花費巨大的內省費用你正在裝飾每個函數,而不是每次調用結果包裝器時)。在像你這樣的情況下,你最好知道自己的子類化(子類化是強大的耦合:盲目地做,絕對不可取!),這似乎不太可能成爲一種有價值的技術,所以你不妨明白參數明確。

是的,如果超類的代碼劇烈變化(例如,,通過改變方法簽名),你也必須修改子類 - 這是繼承的價格(的一部分)。整體價格的大幅足夠新Go編程語言完全不無它 - 迫使你到Gang of 4的優秀建議適用於prefer composition over inheritance。在Python完全禁慾繼承只會是不切實際的,但使用它清醒和適度(並接受的價格,你將支付的耦合而言,當你做)仍然可取。

+0

對簽名變更的警告。但我認爲有一個例外:可以更改構造函數的簽名。問題中描述的問題也適用於構造函數。 – 2009-11-11 17:33:36

相關問題