Reputation: 183
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
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
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