2010-09-21 64 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