2017-01-27 15 views
3

MyClassは、module.pyで定義されています。それを修正する方法はありません。私はモジュールをインポートして、オブジェクトのインスタンスを宣言すると、私のスクリプトを起動クラスの拡張方法

class MyClass: 
    def method(self, msg): 
     print 'from method:', msg 

import module  
foo = module.MyClass() 

その後、私は自分自身の関数を書く:

しかし、私たちは、クラス定義は次のようになります知っています
def function(msg): 
    print 'from function:', msg 

foo.method('')が使用されるたびに、私はfunction()に電話して同じメッセージも出力するようにしたいと思います。

この状況をmonkey patchingと呼びますか?何が必要なのか?投稿1よりよいがあるまで、この解決策になってしまった

+1

サブクラスそれとオーバーライド 'メソッド()'と'super()'を使って基本クラスの 'method()'を呼び出します。 –

+2

サブクラスを作成するだけではない理由はありますか? –

+0

申し訳ありませんが、私は 'MyClass'を継承することができません。 – alphanumeric

答えて

3

はい、それはサルのパッチ適用と呼ばれています。

これは基本的に装飾ですが、クラスが既に定義された後に手動で行われます。

from functools import wraps 

def wrapper(f): 
    @wraps(f) 
    def wrapped(*args, **kwargs): 
     myFunction() 
     return f(*args, **kwargs) 
    return wrapped 

MyClass.printThis = wrapper(MyClass.printThis) 

それも、これらのパッチが適用される前に作成されたもの、MyClassのすべてのインスタンスに影響します。あなたが動的に実行時の動作を変更する必要がない場合は

、避ける猿パッチングコメントで示唆したようは、動作をカスタマイズするために、継承を使用することを好みます。それほどハッキリじゃない。

-1

...

class MyClass: 
    def method(self, msg): 
     print 'from method:', msg 

def function(msg, callback): 
    print 'from function:', msg 
    callback(msg) 

foo = MyClass() 
foo.function = function 
foo.function(msg='message', callback=foo.method) 
+3

'method()'が呼び出されるたびに 'function()'を呼び出す方法は? –

+0

ここで、 'function'が呼び出されるたびに' callback'を介して呼び出されるのは 'method()'です。 – alphanumeric

1

あなたは同様にそれをサブクラス化できます

class MyClass: 
    def method(self, msg): 
     print 'from method:', msg 

def function(msg): 
    print 'from function:', msg 

class MyNewClass(MyClass): 
    def method(self, msg): 
     function(msg) 
     MyClass.method(self, msg) 

をなど、それを使用します。

>>> a = MyNewClass() 
>>> a.method("test") 
from function: test 
from method: test 

それとも、あなたがあなたのクラスのPython 2用「新スタイル」クラスを(したい場合 - )あなたのprint文で判断する - ちょうどobjectからMyClass継承を持っているし、その後することができますユーザーsuper

class MyClass(object): # object added here 
    def method(self, msg): 
     print 'from method:', msg 

def function(msg): 
    print 'from function:', msg 

class MyNewClass(MyClass): 
    def method(self, msg): 
     function(msg) 
     super(self.__class__, self).method(msg) # super added here 
+0

私はおそらく 'super(MyNewClass、self).method(msg)'と呼ぶでしょう。あなたの呼び出しスキームではうまくいきません。(メソッドはクラスメソッドではありません) – boatcoder

+0

@boatcoder superはPython2で動作しませんクラスは新しいスタイルクラスです(OPの例ではなく、プリントに基づいたpy2です)。彼らが新しいスタイルに調整したい場合の例を追加しました:) – NikT

+0

古いスタイルのクラスの良いキャッチ、私は気付かなかった。 – boatcoder

1

wim's answerの代わりに、これはサルのパッチ適用も含まれます。しかし、それはunittest.mockによって提供される機能によってそれを行います。このアプローチの利点は、コンテキストマネージャは自動的に制限された範囲内にパッチを適用し、除去するために使用されていることである。

from unittest import mock 

# This class would be defined in some third-party library 
class MyClass: 
    def method(self, msg): 
     print('from method:', msg) 


def function(msg): 
    print('from function:', msg) 


old_method = MyClass.method 


def new_method(self, msg): 
    old_method(self, msg) 
    function(msg) 


# The patch is only applied within this scope 
with mock.patch.object(MyClass, 'method', new_method): 
    foo = MyClass() 
    foo.method('message with patched') 

# By this point MyClass is "back to normal" 
print('---') 
foo.method('message with original') 

出力

from method: message with patched 
from function: message with patched 
--- 
from method: message with original 
関連する問題