猴子补丁 Python 类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3765222/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 12:38:48  来源:igfitidea点击:

Monkey-patch Python class

pythonmonkeypatching

提问by ZooKeeper

I've got a class, located in a separate module, which I can't change.

我有一个类,位于一个单独的模块中,我无法更改。

from module import MyClass

class ReplaceClass(object)
  ...

MyClass = ReplaceClass

This doesn't change MyClass anywhere else but this file. However if I'll add a method like this

除了这个文件之外,这不会改变 MyClass 的任何其他地方。但是,如果我要添加这样的方法

def bar():
   print 123

MyClass.foo = bar

this will work and foo method will be available everywhere else.

这将起作用并且 foo 方法将在其他任何地方可用。

How do I replace the class completely?

如何完全替换课程?

采纳答案by Glenn Maynard

import module
class ReplaceClass(object):
    ....
module.MyClass = ReplaceClass

回答by Alex Martelli

Avoid the from ... import(horrid;-) way to get barenames when what you need most often are qualifiednames. Once you do things the right Pythonic way:

from ... import当您最需要的是限定名称时,避免使用(可怕的;-)获取裸名的方法。一旦你以正确的 Pythonic 方式做事:

import module

class ReplaceClass(object): ...

module.MyClass = ReplaceClass

This way, you're monkeypatching the moduleobject, which is what you need and will work when that module is used for others. With the from ...form, you just don't havethe module object (one way to look at the glaring defect of most people's use of from ...) and so you're obviously worse off;-);

这样,您就可以对模块对象进行猴子修补,这正是您所需要的,并且在该模块用于其他模块时会起作用。随着from ...形式,你只是不具备模块对象(单程来看看大多数人的使用的怒视缺陷from ...)等你显然更糟;-);

The one way in which I recommend using the fromstatement is to import a module from within a package:

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

from some.package.here import amodule

so you're still getting the module object and will use qualified names for all the names in that module.

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

回答by shahjapan

import some_module_name

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

some_module_name.MyClass = MyClass

Its preferable not to change the name of class while replacing, because somehow someone may have referenced them using getattr - which will result in fail like below

最好不要在替换时更改类的名称,因为有人可能以某种方式使用 getattr 引用了它们 - 这将导致如下失败

getattr(some_module_name, 'MyClass')--> which will fail if you have replaced MyClass by ReplaceClass !

getattr(some_module_name, 'MyClass')--> 如果你用 ReplaceClass 替换了 MyClass 将会失败!

回答by chernevik

I am but an egg . . . . Perhaps it is obvious to not-newbies, but I needed the from some.package.module import moduleidiom.

我不过是一个鸡蛋。. . . 也许对非新手来说很明显,但我需要这个from some.package.module import module习语。

I had to modify one method of GenerallyHelpfulClass. This failed:

我不得不修改 GeneralHelpfulClass 的一种方法。这失败了:

import some.package.module

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

some.package.module.GenerallyHelpfulClass = SpeciallyHelpfulClass

The code ran, but didn't use the behaviors overloaded onto SpeciallyHelpfulClass.

代码运行了,但没有使用在 SpeciallyHelpfulClass 上重载的行为。

This worked:

这有效:

from some.package import module

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

module.GenerallyHelpfulClass = SpeciallyHelpfulClass

I speculate that the from ... importidiom 'gets the module', as Alex wrote, as it will be picked up by other modules in the package. Speculating further, the longer dotted reference seems to bring the module into the namespace with the import by long dotted reference, but doesn't change the module used by other namespaces. Thus changes to the import module would only appear in the name space where they were made. It's as if there were two copies of the same module, each available under slightly different references.

我推测from ... import习语“获取模块”,正如亚历克斯所写的那样,因为它将被包中的其他模块接收。进一步推测,较长的点状引用似乎将模块带入了通过长点状引用导入的名称空间,但不会更改其他名称空间使用的模块。因此,对导入模块的更改只会出现在进行更改的名称空间中。就好像同一个模块有两个副本,每个副本都在略有不同的引用下可用。