How can I build python call tracking capability?

Suppose I have python code for example. some class defined somewhere that cannot be changed

class MyClass(object):

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

      

Now I want to add a trace function for example. some mechanism externally that keeps track of each method is called for the above class. I want to be able to print out when, for example, __init__

was called, or foo

or even a method __del__

MyClass

.

Can this be done, and what is the best way to do it?

+3


source to share


4 answers


Create a proxy class that wraps the original class and then delegates work after printing the trace:



 class MyClassProxy(object):

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

      def foo(self):
           print 'Fooing'
           return self.o.foo()

      

+2


source


You can create a trace decorator and attach it to all methods for defining an instance of a class or class, as shown in 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')

      



The script output will be:

TRACE: func1 () {}
TRACE: func2 ('bar1',) {'b': 'bar2'}
TRACE: func1 (<__main__.TestClass object at 0x7f5a8d888150>,) {}
TRACE: func2 (<__main__.TestClass object at 0x7f5a8d888150>, 'bar1') {'b': 'bar2'}

      

+2


source


Use a decorator like below:

def call_trace(orig_func):

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

      

Use this decorator to trace the function. It prints the name of the function before entering the function.

Example:

@call_trace
def foo(self):
    do_something

      

Hope it helps.

[Update]: you can use the metaclass, only you have to change to add the "metaclass" parameter to your class as shown below. As you can see, the code below applies the "call_trace" decorator to every function in the "ExBase" class.

I tried this yesterday, it worked fine. I am also new to 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()

      

+1


source


Get the code for OnlinePythonTutor from github.com/pgbovine/OnlinePythonTutor/tree/master/v3.

You don't have to worry about all the JS stuff. Extract the files to some directory. You can run your scripts with python / path / to / my / OnlinePythonTutor-master / v3 / generate_json_trace my_script.py

This will basically give you everything your program does step by step. It will probably be overkill, so if you want to look at the source code and the original source at bdb http://docs.python.org/2/library/bdb.html . The docs for bdb are terrible so I have a hard time figuring out what exactly is going on, but I think this is a pretty cool problem, good luck.

0


source







All Articles