【问题标题】:Python class method decoratorPython 类方法装饰器
【发布时间】:2015-12-12 16:02:11
【问题描述】:

我为类方法写了一个装饰器

def decor(method):
    def wrapped(self, *args, **kwargs):
        return method(self, *args, **kwargs)
    # [*]
    return wrapped

我想这样使用:

class A(metaclass=mymetaclass):
    @decor
    def meth(self):
        pass

如何在装饰器中将方法/变量添加到具有装饰方法的类?我需要它在[*] 附近做。 里面包裹着我可以写self.__class__,但是在这里做什么呢?

【问题讨论】:

标签: python python-decorators


【解决方案1】:

我无法想象满足这种要求的方法,因为decor 函数只接收一个对包含类一无所知的函数对象。

我能想到的唯一解决方法是使用参数化装饰器并将被装饰的类传递给它

def decor(cls):
    def wrapper(method):
        def wrapped(self, *args, **kwargs):
            return self.method(*args, **kwargs)
        print method   # only a function object here
        return wrapped
    print cls  # here we get the class and can manipulate it
    return wrapper

class A
    @decor(A)
    def method(self):
        pass

或者,您可以装饰类本身:

def cdecor(cls):
    print 'Decorating', cls  # here we get the class and can manipulate it
    return cls

@cdecor
class B:
    def meth(self):
        pass

给予:

Decorating __main__.B

【讨论】:

    【解决方案2】:

    根据这个回复,看起来这不是直接可能的:

    Get Python function's owning class from decorator

    你可以做的是为你的班级提供一个装饰器,就像这样:

    class InsertMethod(object):
        def __init__(self, methodToInsert):
            self.methodToInsert = methodToInsert
    
        def __call__(self, classObject):
            def wrapper(*args, **kwargs):
                setattr(classObject, self.methodToInsert.__name__, self.methodToInsert)
                return classObject(*args, **kwargs)
            return wrapper
    
    def IWillBeInserted(self):
        print "Success"
    
    
    @InsertMethod(IWillBeInserted)
    class Something(object):
        def __init__(self):
            pass
    
        def action(self):
            self.IWillBeInserted()
    
    
    a = Something()
    a.action()
    

    【讨论】:

      【解决方案3】:

      其实你可以自己装饰类:

      def class_decorator(class_):
          class_.attribute = 'value'
          class_.method = decorate(class_.method)
          return class_
      
      @class_decorator
      class MyClass:
          def method(self):
              pass
      

      【讨论】:

        【解决方案4】:

        我参加聚会有点晚了,但迟到总比没有好,嗯? :)

        我们可以通过使用装饰器来装饰我们的类方法来做到这一点,装饰器本身就是一个类对象,比如B,然后挂钩到 Python 调用 B.__get__ 以获取方法的时刻。在 __get__ 调用中,将同时传递所有者类和该类的新生成实例,您可以选择将您的方法/变量插入到原始所有者类中,或插入到新定义的实例中。

        class B(object):
            def __init__(self, f):
                self.f = f
        
            def __call__(self, *args, **kwargs):
                return self.f(*args, **kwargs)
        
            def __get__(self, instance, owner):
        
                instance.inserted = True
                # owner.inserted = True
                def wrapper(*args, **kwargs):
                    return self(instance, *args, **kwargs)
                return wrapper
        
        class A:
            @B
            def method(self):
                pass
        
        if __name__ == "__main__":
            a = A()
            a.method()
            b = A()
        
            print(hasattr(a, 'inserted'))
            print(hasattr(b, 'inserted'))
        
        

        在此示例中,我们将 def method(self) 包装为 @B。如所写,插入的属性inserted 将仅保留在a 对象中,因为它被应用于实例。如果我们要创建第二个对象b,如图所示,则不包括inserted 属性。即,hasattr(a, 'inserted') 打印 Truehasattr(b, 'inserted') 打印 False。但是,如果我们将inserted 应用于owner 类(如注释掉的行中所示),则插入的属性将持续存在于所有未来的A() 对象中。 IE hasattr(a, 'inserted') 打印Truehasattr(b, 'inserted') 打印True,因为b 是在调用a.method() 之后创建的。

        【讨论】:

          【解决方案5】:

          看起来你只是想装饰一个类函数,而不是专门的@classmethod。这是一个简单的方法,当我想在函数返回成功结果时调用类保存函数时:

          def save_on_success(func):
              """ A decorator that calls a class object's save method when successful """
              def inner(self, *args, **kwargs):
                  result = func(self, *args, **kwargs)
                  if result:
                      self.save()
                  return result
              return inner
          

          这是一个如何使用它的例子:

          class Test:
              def save(self):
                      print('saving')
              @save_on_success
              def test(self, var, result=True):
                      print('testing, var={}'.format(var))
                      return result
          

          测试以确保它按预期工作:

          >>> x = Test()
          >>> print(x.test('test True (should save)', result=True))
          testing, var=test True (should save)
          saving
          True
          >>> print(x.test('test False (should not save)', result=False))
          testing, var=test False (should not save)
          False
          

          【讨论】:

            猜你喜欢
            • 2018-07-14
            • 2012-02-09
            • 2014-01-14
            • 2020-01-11
            • 1970-01-01
            • 1970-01-01
            • 2010-10-16
            • 2011-07-25
            • 2019-11-27
            相关资源
            最近更新 更多