Python猴子补丁一个被另一个模块执行的模块

3

我的问题类似于这个问题

不同的是,我不能在thirdpartymodule_b中执行dosomething(),所以我需要对thirdpartymodule_a进行猴子补丁,并在thirdpartymodule_b中执行它时生效。


1
如果thirdpartymodule_b已经导入了thirdpartymodule_a,我很想知道这是否可能。我以前从未能够做到这一点。 - 2rs2ts
你想进行猴子补丁(monkey-patch)操作,使得只有 thirdpartymodule_b 使用补丁版本的 thirdpartymodule_a,而其他模块仍使用旧版本? - warvariuc
@warwaruk 这是正确的,原因是我想在 Django 的第三方应用中修补一个表单,该表单被其视图所使用。 - James Lin
我真的不太明白。如果你在 Django 中“修补第三方应用程序中的表单,并由其视图使用”,难道你不希望其他模块也使用已修补的版本吗? - warvariuc
@warwaruk 是的,我希望相同的模块也应该使用补丁版本。我认为你的答案已经猜到了原因,可能是urls.py导入了类视图,而这个类视图在我的补丁之前就已经导入了表单。 - James Lin
1个回答

3

我认为你提到的问题和你自己的情况并没有什么不同。在两种情况下,模块都会从另一个模块中导入名称,并且您想要修补该名称引用的对象。

在那个问题中,模块是作者编写的,在您的问题中,它是第三方模块。

我认为您的问题在于第三方已经导入了该对象名称,因此如果您尝试替换该模块中驻留的对象,则第三方模块仍将使用旧对象,因为它仍然引用旧对象。

module_1.py

class AForm(Form):
    ...

module_2.py

from module_1 import AForm

如果您导入module_2并且使用monkey-patch替换AForm为另一个对象。
class AFormPatched(Form):
    ...

import module_1
module_1.AForm = AFormPatched

你所做的更改不会影响module_2,因为module_2.AForm仍然指向原始对象。

要解决这个问题:

选项1。 module_2应该像这样:

import module_1
module_1.AForm  # using AForm in this form

选项2。 也要修补 module_2.AForm:

class AFormPatched(Form):
    ...

import module_1
module_1.AForm = AFormPatched
import module_2
module_2.AForm = AFormPatched

或者不要修补您只想使module_2使用修补程序版本的module_1
选项3. 修补对象的属性。如果您不想或无法猴子补丁使用对象名称的所有位置,有时如果您不替换对象,而仅修补其某些属性,则可以起作用。这取决于对象和您尝试修补的行为。
import third_party_module
third_party_module.AForm.__init__ = ...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接