2010-09-21 57 views
39

我有一個類,位於一個單獨的模塊中,我無法更改。Monkey-patch Python class

from module import MyClass 

class ReplaceClass(object) 
    ... 

MyClass = ReplaceClass 

這不會改變MyClass在其他地方,但這個文件。但是,如果我要添加這樣的方法

def bar(): 
    print 123 

MyClass.foo = bar 

這將工作,foo方法將在其他地方提供。

如何完全替換類?

回答

52
import module 
class ReplaceClass(object): 
    .... 
module.MyClass = ReplaceClass 
+3

+1更快。只要確保它在任何使用'module的導入之前運行。MyClass' – aaronasterling 2010-09-21 23:32:07

+0

速度越快越不正確,但我並不認爲這需要額外的解釋。一旦你看到如何去做,差異應該是非常明顯的。 – 2010-09-21 23:37:24

+15

確保您是導入課程的「第一個」。已經引用「舊」類不會被替換! – 2010-09-22 06:20:53

27

避免from ... import(可怕的;-)的方式來獲得barenames當你最需要的時候是什麼合格名。一旦你做的事情正確的Python的方式:

import module 

class ReplaceClass(object): ... 

module.MyClass = ReplaceClass 

這樣一來,你的Monkeypatching的模塊對象,這是你需要什麼,當模塊用於別人會工作。使用from ...表格,你只是不要模塊對象(一種方法來看看大多數人使用from ...的明顯缺陷),所以你顯然更糟糕;-);

中,我建議使用from聲明的一個方法是從一個包中導入了一個模塊:

from some.package.here import amodule 

所以你仍然得到模塊對象,將使用限定名稱爲所有的名字在該模塊中。

+2

+1但注意'module.MyClass =',雖然它會替換模塊中的類,但不會替換已經從模塊導入MyClass中完成的任何其他模塊中的類。他們將擁有自己的單獨副本。猴子補丁是不好的mmkay; '從模塊導入'也是不好的mmkay;在同一時間,這是一個錯誤的東西的祕訣。 – bobince 2010-09-21 23:43:20

+3

@bobince,絕對!如果其他代碼的其他部分也使用我從模塊導入MyClass中引用的'''',那麼發現和嘲諷所有這些代碼都處於「亂七八糟」和「不可能」之間('gc.get_referrers''s sometimes_ help。 .. 但不總是_!-)。是的,他們都是不好的做法,但有時候monkeypatching可以成爲最小的弊端,而用'from'語句創建「artificial barenames」可以總是被忽視。 – 2010-09-21 23:49:03

+0

這是解決我的問題的一點。 – chernevik 2011-10-20 01:38:51

1
import some_module_name 

class MyClass(object): 
    ... #copy/paste source class and update/add your logic 

some_module_name.MyClass = MyClass 

它最好不要改變類的名稱,同時更換,因爲在某種程度上可能是有人利用GETATTR引用它們 - 這將導致失敗,像下面

getattr(some_module_name, 'MyClass') - 如果你有>將失敗用ReplaceClass替換MyClass!

+0

1)這隻會在執行導入的模塊中生效:添加'as foo'不會有任何幫助。 2)你對getattr的爭論不僅僅是混淆(因爲你不一致地使用了名字),而且也是錯誤的,並且把類的名字和類本身混淆了。如果我輸入一些模塊; somemodule.someclass = someotherclass',然後在另一個模塊中,'getattr(somemodule,'someclass')'將返回'其他類',這正是OP想要的。 3)複製粘貼編程是醜陋的和容易出錯的。 – aaronasterling 2010-09-22 05:49:09

+0

@AaronMcSmooth,同意!,現在我已經編輯了答案,但由於OP想要替換整個類,所以我寫了複製/粘貼和添加/更新邏輯,因爲它不可能繼承原始類,因爲我們是會取代它,如果OP想更新邏輯只有幾行,然後休息他需要從原始來源得到的代碼! – shahjapan 2010-09-22 06:27:08

+0

現在你的解決方案和已經出現的關於'getattr'的一個(仍然是!)錯誤陳述的缺陷已經出現的兩個一樣了。另外,爲什麼我們不能從我們將要替換的類繼承「? 'class A(object):pass; B類(A):通過; A = B; a = A()'。 – aaronasterling 2010-09-22 06:53:17

9

我只是一個蛋。 。 。 。也許對非新手來說很明顯,但我需要這個成語。我不得不修改OrdinaryHelpfulClass的一個方法。這失敗了:

import some.package.module 

class SpeciallyHelpfulClass(some.package.module.GenerallyHelpfulClass): 
    def general_method(self):... 

some.package.module.GenerallyHelpfulClass = SpeciallyHelpfulClass 

該代碼運行,但未使用重載到SpeciallyHelpfulClass上的行爲。

這工作:

from some.package import module 

class SpeciallyHelpfulClass(module.GenerallyHelpfulClass): 
    def general_method(self):... 

module.GenerallyHelpfulClass = SpeciallyHelpfulClass 

我推測from ... import成語「獲取模塊」,亞歷克斯寫了,因爲它會通過在包中的其它模塊有所回升。進一步推測,較長的虛線引用似乎通過長點引用將模塊帶入名稱空間,但不會更改其他名稱空間使用的模塊。因此,對導入模塊的更改只會出現在它們所在的名稱空間中。就好像有兩個相同模塊的副本,每一個都可以在稍微不同的參考下使用。

+3

+1,因爲我覺得它更有助於討論擴展想要修補的類,然後替換它,而不僅僅是擴展Object並替換它。 – 2012-08-30 21:17:55