3

たとえば、どこかで定義された、変更できないクラスなど、いくつかの Python コードがあるとします。

class MyClass(object):

    def __init__(self, arg1, arg2):
        do_something...
    def foo(self):
        do_something

ここで、トレース機能を追加したいと思います。たとえば、上記のクラスのすべてのメソッド呼び出しをトレースする外部からのメカニズムです。たとえば、__init__が呼び出されたとき、fooまたは.__del__MyClass

これを行うことは可能ですか? また、どのように行うのが最善ですか?

4

4 に答える 4

2

元のクラスをラップし、トレースを出力した後に作業を委任するプロキシ クラスを作成します。

 class MyClassProxy(object):

      def __init__(*args, **kwds):
           print 'Initializing'
           self.o = MyClass(*args, **kwds)

      def foo(self):
           print 'Fooing'
           return self.o.foo()
于 2013-02-08T06:27:03.850 に答える
2

関数に示すように、トレース デコレータを作成して、クラス インスタンスまたはクラス定義のすべてのメソッドにアタッチできますdecorate_methods

import functools
import inspect
import types

class TestClass(object):
    def func1(self):
        pass

    def func2(self, a, b):
        pass

def trace(func):
    @functools.wraps(func)
    def decorator(*args, **kwargs):
        print "TRACE:", func.__name__, args, kwargs
        return func(*args, **kwargs)
    return decorator

def decorate_methods(obj, decorator):
    for name, func in inspect.getmembers(obj):
        if isinstance(func, types.MethodType):
            setattr(obj, name, decorator(func))

# Apply the decorator to a class instance
test1 = TestClass()
decorate_methods(test1, trace)
test1.func1()
test1.func2('bar1', b='bar2')

# Apply the decorator to the class definition
decorate_methods(TestClass, trace)
test2 = TestClass()
test2.func1()
test2.func2('bar1', b='bar2')

スクリプトの出力は次のようになります。

TRACE: func1 () {}
TRACE: func2 ('bar1',) {'b': 'bar2'}
TRACE: func1 (<__main__.TestClass object at 0x7f5a8d888150>,) {}
TRACE: func2 (<__main__.TestClass object at 0x7f5a8d888150>, 'bar1') {'b': 'bar2'}
于 2013-02-08T07:50:56.083 に答える
1

以下に示すようにデコレータを使用します。

def call_trace(orig_func):

    def decorated_func(*args, **kwargs):
        print "========>In function: " + orig_func.__name__ + "<========"
        orig_func(*args, **kwargs)
    return decorated_func

このデコレータを適用して関数をトレースします。関数に入る前に関数名を出力します。

元:

@call_trace
def foo(self):
    do_something

それが役に立てば幸い。

[更新]: メタクラスを使用できます。変更する必要があるのは、以下に示すように、クラスに「メタクラス」パラメーターを追加することだけです。ご覧のとおり、以下のコードは「call_trace」デコレーターをクラス「ExBase」のすべての関数に適用します。

昨日これを試してみましたが、うまくいきました。私はPythonも初めてです。:)

def call_trace(orig_func):

    def inner_func(*args, **kwargs):
        print ("function name:" + str(orig_func.__name__))
        orig_func(*args, **kwargs)
    return inner_func

class ExMeta(type):

    def __new__(cls, name, bases, attrs):

        for attr in attrs:
            if hasattr(attrs[attr], '__call__'):
                attrs[attr] = call_trace(attrs[attr])
        return type.__new__(cls, name, bases, attrs)

class ExBase(metaclass=ExMeta):

    x = "x"
    y = "y"
    def __init__(self):
        self.__name = "name"

    def getname(self):
        return self.__name

b = ExBase()
b.getname()
于 2013-02-08T06:37:43.457 に答える
0

github.com/pgbovine/OnlinePythonTutor/tree/master/v3 から OnlinePythonTutor のコードを取得します。

すべての JS を気にする必要はありません。ファイルをいくつかのディレクトリに抽出します。python /path/to/my/OnlinePythonTutor-master/v3/generate_json_trace my_script.py を使用してスクリプトを実行できます

これにより、基本的にプログラムが行っているすべてのことを段階的に行うことができます。おそらくやり過ぎになるので、ソースコードと bdb http://docs.python.org/2/library/bdb.htmlの基礎となるソースを調べたい場合。bdb のドキュメントはひどいので、正確に何が起こっているのかを理解するのに苦労していますが、これはかなりクールな問題だと思います。頑張ってください。

于 2013-02-08T08:13:04.527 に答える