2016-06-01 11 views
1

私はライブラリにいくつかの非常に基本的な機能(scikit-learn)を追加しようとしています。しかし、私は直接ライブラリ自体を変更したくないと思っています。それは、自分のテストでも、機能をオン/オフにする機能を持っていると思います.b)これはおそらく、ライブラリのメインコードベース。Pythonでライブラリからクラスを完全に猿にパッチすることは可能ですか?

基本クラス(この場合は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であることが考えられます。

from ..base import BaseEstimator 

がサル・パッチにPythonで輸入品のこのスタイルも可能です:sklearn /アンサンブル/ base.pyを見てみると、一つは以下の見ていますか?さらに重要なのは、プログラムのコンテキスト内では、明らかにどこでどのようにインポートされるかにかかわらず、このクラスのすべてのインスタンスをサルパッチすることは可能ですか?

理想的には、エンドゲームは、このようなものになるだろう:

import my_module 
from sklearn.(anything) import SomeEstimator 

SomeEstimator() # this runs my code in addition to SomeEstimator's code 
... 

答えて

1

問題はその子供たちがsuper.__init__を呼び出すことはありませんので、BaseEstimatorは、__init__メソッドを定義していないということです。しかし、あなたがサルのパッチBaseEnsembleを適用すると、その効果が表示されます。クラスを交換すると、他のクラスがすでに元のクラスをサブクラス化しているように非常に効果的ではありませんが、あなたはそうのようなクラスのメソッドを置き換えることができます。これは確かにcalledを印刷ん

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() 

+0

Doh!私は '__init__'の欠如に気付かなかったとは信じられません。私はちょうどそれが1つを持っていると仮定したと思います! –

関連する問題