如何通过Monkey Patch修改模块内被类调用的函数以改变类的行为?
如何通过Monkey Patch修改模块内被类调用的函数以改变类的行为?
我来帮你解决这个问题~你遇到的核心问题是找错了要patch的对象位置,咱们一步步来理清楚:
为什么你的尝试没成功?
- 第一种patch方式:你修改的是
my_library._do_something,但foo类的bar方法里调用的是**_module.py模块内部**的_do_something,不是my_library命名空间里的这个引用,所以根本没影响到类的调用逻辑。 - 第二种导入方式:因为你的
__init__.py只导出了foo,没有把_do_something暴露出来,所以直接从my_library导入它肯定会报错。
正确的Monkey Patch方法
你需要直接找到函数实际定义的那个模块(也就是my_library._module),然后修改该模块里的函数引用,这样类调用时才会使用新的函数。具体代码如下:
# 导入内部模块 import my_library._module # 替换模块内的_do_something函数 my_library._module._do_something = lambda: print('goodbye') # 再创建foo实例调用方法 a = my_library.foo() a.bar() # 现在会输出'goodbye'
或者也可以这样写,更直观:
from my_library._module import foo import my_library._module as inner_module # 注意:必须修改模块命名空间里的函数,不能只改局部变量 inner_module._do_something = lambda: print('goodbye') a = foo() a.bar() # 输出'goodbye'
原理说明
模块里的类在引用同模块的函数时,是直接绑定到模块的命名空间上的。你之前修改的要么是外部命名空间的引用,要么是局部变量,都没触达类实际依赖的那个模块内的函数对象。只有修改函数所在模块的命名空间中的对应变量,才能让类的调用逻辑切换到新函数。
对应到你的sklearn场景
针对你提到的sklearn.mixture.GaussianMixture和_estimate_gaussian_parameters的情况,逻辑完全一致:
- 先找到
_estimate_gaussian_parameters实际定义的模块(比如它可能在sklearn.mixture._gaussian_mixture这类内部模块里) - 导入那个内部模块,然后patch该模块里的
_estimate_gaussian_parameters函数 - 之后创建
GaussianMixture实例时,它的方法就会使用你修改后的函数了
备注:内容来源于stack exchange,提问作者leoneu
相关产品推荐
相关产品推荐

