有可能完全用Python中的库对类进行猴子补丁吗



我正在尝试为库添加一些非常基本的功能(即scikit-learn)。然而,我宁愿不直接修改库本身,因为a)即使在我自己的测试中,我也希望能够打开和关闭功能,b)这很可能是不属于库主代码库的功能。

我想做的是对基类(在本例中为sklearn.base.BaseEstimator)进行猴子补丁,这样当库中的其他类从该类导入/派生时,它们会得到我修改过的类。到目前为止,我拥有的是:

import sklearn
from sklearn.base import BaseEstimator
from sklearn import base
class InstrumentedEstimator(sklearn.base.BaseEstimator):
def __init__(self, *args, **kwargs):
print 'called'
super(InstrumentedEstimator, self).__init__(*args, **kwargs)
sklearn.base.BaseEstimator = InstrumentedEstimator
base.BaseEstimator = InstrumentedEstimator
BaseEstimator = InstrumentedEstimator
from sklearn.ensemble import RandomForestClassifier
RandomForestClassifier()

这不起作用,即RandomForestClassifier()不打印called。我怀疑这里的主要原因是,当查看RandomForestClassifier的层次结构时,从BaseEstimator派生的最终父类是sklearn.ensemble.base.BaseEnsemble。查看sklearn/integration/base.py,可以看到以下内容:

from ..base import BaseEstimator

有可能在Python中对这种风格的导入进行猴子补丁吗?更重要的是,是否有可能(显然是在程序的上下文中)对该类的所有实例进行猴子补丁,而不管它们是在哪里以及如何导入的?

理想情况下,最终游戏应该是这样的:

import my_module
from sklearn.(anything) import SomeEstimator
SomeEstimator()  # this runs my code in addition to SomeEstimator's code
...

问题是BaseEstimator没有定义__init__方法,所以它的子级不会调用super.__init__。然而,如果你对BaseEnsemble进行猴子补丁,你会看到效果。替换类不是很有效,因为其他类已经将原始类子类化了,但您可以替换类上的方法,如下所示:

from sklearn.ensemble import BaseEnsemble, RandomForestClassifier
old_init = BaseEnsemble.__init__
def new_init(*args, **kwargs):
print 'called'
old_init(*args, **kwargs)
BaseEnsemble.__init__ = new_init
RandomForestClassifier()

这确实打印了called

相关内容

  • 没有找到相关文章

最新更新