Search this site


Metadata

Articles

Projects

Presentations

Wrap method calls in python

Function wrapping is quite useful, especially when you need to make code threadsafe by wrapping with a mutex locker or adding debug entry/exit traces. We can easily wrap methods in python using lambda.

A standalone module for wrapping can be found here: wrap.py If you don't understand what the * and ** stuff means, that's fine. I'll post about those shortly.

A fun, crappy example can be found here: wrapexample.py

That example shows how to wrap a simple method (X.Foo) with pre- and post-execution function calls. Notice how we can access the parameters passed to the original function (Foo) in both the pre and post functions. That's all good and pretty, but how about a better example?

A better example would be to wrap a function call with a mutex locker.

Let's take an example class happyfoo. A sample script that uses happyfoo can be found here: main.py. However, time passes and now I require the happyfoo.makenoise method to be locked while we are inside it. If you look at the code, it doesn't lock and is not threadsafe (for our purposes).

In an ideal situation, you might add locking to the 'happyfoo.py' module itself. What if you can't do that (no access) or don't have time to hack through the code? There's an easier way.

Python lets you modify classes at runtime. The new locking code can be found here: main-locking.py

The coolest part about this is I do not have to modify the 'happyfoo.py' module. Perhaps this is a dangerous feature, but I think it's neat. Anyway, the bulk of the new code should be self explanatory, with the possible exception of this:

happyfoo.makenoise = wrap.wrapmethod(happyfoo.makenoise, do_lock, do_unlock)
This is where I override the 'happyfoo.makenoise' method with a generated one that calls the original 'happyfoo.makenoise' function wrapped in 'do_lock' and 'do_unlock' functions. If you run the script, you'll see it locking aswell as the threads waiting for the lock.

If you want to download all of the code from the post, try this tarball: python-method-wrapper.tar.gz

The wrap module needs a lot of work, potentially. It would be nice to be able to wrap and also pass other arguments to both pre and post functions. I've got a hack that adds a reference to the function being called to the keyword (kwds) list, which lets you figure out which function is actually being called. Useful if you use the same pre/post functions to wrap more than one function.