Tempster102
Tempster102

Reputation: 183

Python capture method call and parameters

I'm trying to capture a function call from a singleton class without override the method.

Currently I'm doing this:

class MyClass
    oldMethod = None

    def __init__(self):
        c = Class.Instance()
        self.oldMethod = c.Method #make a copy to the pointer of the original function
        c.Method = self.NewMethod #redirect it

    def NewMethod(self, x, a):
        self.oldMethod(x, a) #call the old function
        #My Stuff

I'm trying to capture the 'event' (being the method call) and the parameters of this method call. Is there any other way to do this to says 'passively' capture it, just listen and get the parameters.

Note: I do not have access to the code of singleton class.

Thanks

Upvotes: 2

Views: 2879

Answers (2)

Marwan Alsabbagh
Marwan Alsabbagh

Reputation: 26788

You mentioned that you want to intercept the method calls during normal operations and not just during debugging. This solution is a different approach then the other answer, it uses the Proxy pattern approach of making a new object that will be a sort of wrapper to all the calls to the original object. On the proxy level you can log and monitor the calls as needed.

person.py

To demonstrate the code I've created an example class called Person in person module. We can pretend this is the module which you cannot modify the code.

class Person(object):
    def __init__(self, name=None):
        self.name = name

    def greet(self, greeting='hello'):
        print '%s %s' % (greeting, self.name)

    def __repr__(self):
        return "Person(%r)" % self.name

example.py

In the code below we create a proxy object called ProxyPerson which when used instead of Person behaves identically to it and has the added behavior of logging all calls to the greet method. You notice that it uses *args, **kwargs so Person might have a different signature in the future but the code won't break if changes are made.

import person

class ProxyPerson(person.Person):
    def greet(self, *args, **kwargs):
        print '--- greet() self=%r args=%r kwargs=%r' % (self, args, kwargs)
        super(ProxyPerson, self).greet(*args, **kwargs)

#person.Person = ProxyPerson #uncomment to monkey patch Person

jack, jill = person.Person('Jack'), ProxyPerson('Jill')
for p in jack, jill:
    p.greet()
    p.greet('hi')
    p.greet(greeting='why hello')

Regular output

The output below shows the difference in execution when the original Person class is is used or when the ProxyPerson is used. The examples also include calls with no positional arguments, with positional arguments, and finally with keyword arguments.

hello Jack
hi Jack
why hello Jack
--- greet() self=Person('Jill') args=() kwargs={}
hello Jill
--- greet() self=Person('Jill') args=('hi',) kwargs={}
hi Jill
--- greet() self=Person('Jill') args=() kwargs={'greeting': 'why hello'}
why hello Jill

Monkey patched output

Finally one can Monkey patch person.Person class to point to ProxyPerson. You can experiment with this approach by commenting out the monkey patch line in example.py. The output in this case would be as follows:

--- greet() self=Person('Jack') args=() kwargs={}
hello Jack
--- greet() self=Person('Jack') args=('hi',) kwargs={}
hi Jack
--- greet() self=Person('Jack') args=() kwargs={'greeting': 'why hello'}
why hello Jack
--- greet() self=Person('Jill') args=() kwargs={}
hello Jill
--- greet() self=Person('Jill') args=('hi',) kwargs={}
hi Jill
--- greet() self=Person('Jill') args=() kwargs={'greeting': 'why hello'}
why hello Jill

The benefits of monkey patching are that all future instances of person.Person will in fact be instances of the proxy object that has been created. Monkey patching comes with it's own set of issues that you should keep in mind before using it.

Upvotes: 3

Marwan Alsabbagh
Marwan Alsabbagh

Reputation: 26788

You could use winpdb it's a great easy to use graphical debugger for python. So you Just open the python script in question, setup a breakpoint at whatever methods in whatever classes you want to watch. It will pause at that point and showing you the state of variables and what not at each call to that method.

Upvotes: 0

Related Questions