Python:使用前后方法包裹方法调用

9 投票
6 回答
12713 浏览
提问于 2025-04-11 09:33

我正在我的类 X 中创建一个类 A 的实例(这个类 A 是从别人那里导入的,所以我不能修改它)。

有没有办法可以拦截或包装对 A 中方法的调用?

也就是说,在下面的代码中,我能否调用

x.a.p1()

并得到输出

X.pre
A.p1
X.post

非常感谢!

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

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

x=X()
x.a.p1()

6 个回答

1

一个简单直接的解决办法就是为A类写一个包装类,专门用来做这个事情。

3

你可以直接修改A这个实例,把p1这个函数换成一个包装函数:

def wrapped(pre, post, f):
    def wrapper(*args, **kwargs):
        pre()
        retval = f(*args, **kwargs)
        post()
        return retval
    return wrapper

class Y:
    def __init__(self):
        self.a=A()
        self.a.p1 = wrapped(self.pre, self.post, self.a.p1)

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

这是我和我的同事们想出的解决办法:

from types import MethodType

class PrePostCaller:
    def __init__(self, other):
        self.other = other

    def pre(self): print 'pre'
    def post(self): print 'post'

    def __getattr__(self, name):
        if hasattr(self.other, name):
            func = getattr(self.other, name)
            return lambda *args, **kwargs: self._wrap(func, args, kwargs)
        raise AttributeError(name)

    def _wrap(self, func, args, kwargs):
        self.pre()
        if type(func) == MethodType:
            result = func( *args, **kwargs)
        else:
            result = func(self.other, *args, **kwargs)
        self.post()
        return result

#Examples of use
class Foo:
    def stuff(self):
        print 'stuff'

a = PrePostCaller(Foo())
a.stuff()

a = PrePostCaller([1,2,3])
print a.count()

结果是:

pre
stuff
post
pre
post
0

所以在创建你对象的实例时,要把它放在一个叫做 PrePostCaller 的对象里。之后,你可以像使用普通对象一样继续使用这个被包装的对象。这个方法让你可以针对每个实例单独进行包装。

撰写回答