Monkey-patch Python类

Zoo*_*per 45 python monkeypatching

我有一个班级,位于一个单独的模块中,我无法改变.

from module import MyClass

class ReplaceClass(object)
  ...

MyClass = ReplaceClass
Run Code Online (Sandbox Code Playgroud)

除了这个文件之外,这不会改变MyClass.但是,如果我要添加这样的方法

def bar():
   print 123

MyClass.foo = bar
Run Code Online (Sandbox Code Playgroud)

这将工作,foo方法将在其他地方可用.

如何完全替换课程?

Gle*_*ard 59

import module
class ReplaceClass(object):
    ....
module.MyClass = ReplaceClass
Run Code Online (Sandbox Code Playgroud)

  • 确保你是第一个导入课程的人.已经提到"旧"类的引用不会被替换! (16认同)
  • +1更快.只要确保它在使用`module.MyClass`的任何导入之前运行 (3认同)

Ale*_*lli 29

from ... import当你最常需要的是合格的名字时,避免使用(可怕的;-)方式来获取昵称.一旦你做了正确的Pythonic方式:

import module

class ReplaceClass(object): ...

module.MyClass = ReplaceClass
Run Code Online (Sandbox Code Playgroud)

这样,您就可以对模块对象进行monkeypatching ,这是您需要的模块对象,并且当该模块用于其他模块时将会工作.随着from ...形式,你只是不具备模块对象(看大多数人的使用的明显的缺陷的一种方式from ...)等你显然更糟;-);

我建议使用该from语句的一种方法是从包中导入模块:

from some.package.here import amodule
Run Code Online (Sandbox Code Playgroud)

所以你仍然得到模块对象,并将使用该模块中所有名称的限定名称.

  • @bobince,绝对!如果代码的其他部分**也使用了我的detested` from module import MyClass`,那么查找和修改所有这些内容就在"混乱"和"不可能"之间(`gc.get_referrers`可以_sometimes_帮助. .. 但不总是_!-).是的,它们都是不好的做法,但有时monkeypatching可能是最少的邪恶,而使用`from`语句创建"人工吟唱"可以*永远*免除. (3认同)
  • +1但注意`module.MyClass =`,虽然它将替换模块中的类,但不会替换已经完成`from module import MyClass`的任何其他模块中的类.他们将有自己独立的副本.猴子修补是不好的mmkay; `from module import`也很糟糕mmkay; 两者同时是一个错误的东西. (2认同)

che*_*vik 12

我只是一个鸡蛋....对于非新手来说,也许这是显而易见的,但我需要这个from some.package.module import module成语.

我不得不修改一个通常帮助类的方法.这失败了:

import some.package.module

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

some.package.module.GenerallyHelpfulClass = SpeciallyHelpfulClass
Run Code Online (Sandbox Code Playgroud)

代码运行,但没有使用重载到SpeciallyHelpfulClass上的行为.

这有效:

from some.package import module

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

module.GenerallyHelpfulClass = SpeciallyHelpfulClass
Run Code Online (Sandbox Code Playgroud)

我推测from ... import成语'得到模块',正如亚历克斯所写,因为它将被包中的其他模块拾取.进一步推测,较长的虚线引用似乎通过长点引用导入模块进入命名空间,但不会更改其他命名空间使用的模块.因此,对导入模块的更改只会出现在创建它们的名称空间中.就好像有两个相同模块的副本,每个副本都有不同的引用.

  • 这是+1,因为我发现扩展要修补的类然后替换它更有帮助,而不是仅仅扩展Object并替换它. (5认同)