wrapping a method function call?

Steven D'Aprano steven at REMOVE.THIS.cybersource.com.au
Mon Nov 3 04:17:01 EST 2008


On Mon, 03 Nov 2008 08:17:02 +0000, mh wrote:

> I am instantiating a class A (which I am importing from somebody else,
> so I can't modify it) into my class X.
> 
> Is there a way I can intercept or wrape calls to methods in A? I.e., in
> the code below can I call
> 
>    x.a.p1()
> 
> and get the output
> 
>     X.pre
>     A.p1
>     X.post


Possibly you can do it with some metaclass magic. You might like to 
search for Eiffel-style pre- and post-conditions using a metaclass, 
although I warn you, many people consider metaclasses deep voodoo.

Here's one way using decorators:

# Define two decorator factories.
def precall(pre):
    def decorator(f):
        def newf(*args, **kwargs):
            pre()
            return f(*args, **kwargs)
        return newf
    return decorator

def postcall(post):
    def decorator(f):
        def newf(*args, **kwargs):
            x = f(*args, **kwargs)
            post()
            return x
        return newf
    return decorator


Now you can monkey patch class A if you want. It's probably not a great 
idea to do this in production code, as it will effect class A everywhere.

def pre(): print 'X.pre'
def post(): print 'X.post'

from module import A

A.p1 = precall(pre)(postcall(post)(A.p1))


Here's another way:

class A:
    # in my real application, this is an imported class 
    # that I cannot modify
    def p1(self): print 'A.p1'

class WrapA:
    def __init__(self, ainstance, xinstance):
        self._a = ainstance
        self._x = xinstance
    def p1(self):
        # Delegate calls as needed.
        self._x.pre()
        self._a.p1()
        self._x.post()

class X:
    def __init__(self):
        self.a = WrapA(A(), self)
    def pre(self):
        print 'X.pre'
    def post(self): 
        print 'X.post'


There are probably many other ways to accomplish the same thing, 
depending on your exact requirements. You should be able to combine the 
decorator technique and the delegation technique to leave class A 
untouched outside of class X, but wrapped inside of X.



-- 
Steven




More information about the Python-list mailing list