【问题标题】:Create a wrapper class to call a pre and post function around existing functions?创建一个包装类来围绕现有函数调用 pre 和 post 函数?
【发布时间】:2009-09-23 15:19:05
【问题描述】:

我想创建一个包装另一个类的类,这样当一个函数通过包装类运行时,也会运行一个 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")

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

我想要发生的是,当通过包装类调用函数时,包装类中的 pre 函数被调用,然后被包装类中的所需函数然后是 post 函数。我希望能够在不更改包装类以及不更改函数调用方式的情况下做到这一点,只更改创建类实例的语法。例如 number = Simple() vs number = Wrapper(Simple)

【问题讨论】:

    标签: python


    【解决方案1】:

    你快到了,你只需要在__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
    

    【讨论】:

    • 这是一个不错的答案,但如果包装类具有返回包装类的另一个实例的方法,则它不起作用。这不是假设 - 例如,这就是为什么 pandas 包如此难以子类化的原因,正如我在过去几天了解到的那样 :)
    • 也不适用于内部类调用 - 这只会包装来自外部的调用
    【解决方案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"     
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-25
      • 1970-01-01
      • 2021-12-01
      • 2021-04-06
      • 2021-03-26
      • 2018-01-19
      • 1970-01-01
      相关资源
      最近更新 更多