创建一个包装类来围绕现有函数调用前置和后置函数?

2024-05-23 15:28:18 发布

您现在位置:Python中文网/ 问答频道 /正文

我想创建一个包装另一个类的类,这样当一个函数在包装类中运行时,pre和post函数也会运行。我希望包装器类不需要修改就可以与任何类一起工作。

例如,如果我有这门课。

class Simple(object):
    def one(self):
        print "one"

    def two(self,two):
        print "two" + two

    def three(self):
        print "three"

我可以这样用。。。

number = Simple()
number.one()
number.two("2")

到目前为止,我已经编写了这个包装类。。。

class Wrapper(object):
    def __init__(self,wrapped_class):
        self.wrapped_class = wrapped_class()

    def __getattr__(self,attr):
        return self.wrapped_class.__getattribute__(attr)

    def pre():
        print "pre"

    def post():
        print "post"

我可以这样称呼。。。

number = Wrapper(Simple)
number.one()
number.two("2")

除了改变第一行外,也可以和上面一样使用。

我想发生的是,当通过包装类调用函数时,包装类中的前函数被调用,包装类中的所需函数被调用,后函数被调用。我希望能够在不改变包装类的情况下,也不改变函数的调用方式,只改变创建类实例的语法。例如number=Simple()与number=Wrapper(Simple)


Tags: 函数selfnumberobjectdefwrappersimplepost
2条回答

我刚刚注意到,在我最初的设计中,无法将args和kwargs传递给包装类,下面是更新后的答案,以便将输入传递给包装函数。。。

class Wrapper(object):
def __init__(self,wrapped_class,*args,**kargs):
    self.wrapped_class = wrapped_class(*args,**kargs)

def __getattr__(self,attr):
    orig_attr = self.wrapped_class.__getattribute__(attr)
    if callable(orig_attr):
        def hooked(*args, **kwargs):
            self.pre()
            result = orig_attr(*args, **kwargs)
            self.post()
            return result
        return hooked
    else:
        return orig_attr

def pre(self):
    print ">> pre"

def post(self):
    print "<< post"     

您就快到了,只需要在__getattr__内部进行一些自省,在原始属性可调用时返回一个新的包装函数:

class Wrapper(object):
    def __init__(self,wrapped_class):
        self.wrapped_class = wrapped_class()

    def __getattr__(self,attr):
        orig_attr = self.wrapped_class.__getattribute__(attr)
        if callable(orig_attr):
            def hooked(*args, **kwargs):
                self.pre()
                result = orig_attr(*args, **kwargs)
                # prevent wrapped_class from becoming unwrapped
                if result == self.wrapped_class:
                    return self
                self.post()
                return result
            return hooked
        else:
            return orig_attr

    def pre(self):
        print ">> pre"

    def post(self):
        print "<< post"

现在有了这个代码:

number = Wrapper(Simple)

print "\nCalling wrapped 'one':"
number.one()

print "\nCalling wrapped 'two':"
number.two("2")

结果是:

Calling wrapped 'one':
>> pre
one
<< post

Calling wrapped 'two':
>> pre
two2
<< post

相关问题 更多 >