【问题标题】:Accessing class property as decorator argument访问类属性作为装饰器参数
【发布时间】:2020-07-09 10:49:15
【问题描述】:

我正在尝试应用conditional decorator,如另一篇 stackoverflow 帖子中所述,但我希望从正在使用的类内部设置条件。相反,我得到一个引用错误,指出 self 未定义。

class foo:
    def __init__(self):
        self.debug = True

    @conditional_decorator(decorator, self.debug)
    def function(self):
        pass

我尝试定义一个全局变量并从 __init__() 方法内部对其进行更新,但它在作为装饰器的参数调用时保持其原始值。

debug = None

class foo:
    def __init__(self):
        self.debug = True
        global debug
        debug = self.debug

    @conditional_decorator(decorator, debug)
    def function(self):
        pass

它起作用的唯一方法是声明一个全局变量并将其设置在类之外。

如何将类属性的值应用于装饰器?

【问题讨论】:

  • btw decorators 在 python 读取程序文本时应用,而不是在运行时。
  • @quamrana:不,装饰器是在函数定义时应用的。
  • Python 函数定义是命令式的——执行一个会生成一个新的函数对象。在此之后立即应用装饰器。当 Python 读取源代码时,它们不会也不能应用;此时没有函数对象可以传递给装饰器,也可能没有装饰器可以调用。
  • @quamrana 当def 语句被执行时,在运行时。
  • class 语句在运行时执行,这就是为什么类的主体不能引用类本身,因为该类还不存在而尸体正在被处决。

标签: python class decorator


【解决方案1】:

装饰器不应该是有条件的。相反,当调用装饰函数时,它应该查看self.debug 以确定是使用原始函数还是包装部分。

def conditional_decorator(dec):
    def decorator(func):
        def _(self, *args, **kwargs):
            f = func
            if self.debug:
                f = dec(f)
            return f(self, *args, **kwargs)
        return _
    return decorator


def decorator(f):
    def _(*args, **kwargs):
        print("Decorated")
        return f(*args, **kwargs)
    return _


class foo:
    def __init__(self, debug):
        self.debug = debug

    @conditional_decorator(decorator)
    def function(self):
        print("foo stuff")

foo(True).function()
print("===")
foo(False).function()

输出

Decorated
foo stuff
===
foo stuff

【讨论】:

    【解决方案2】:

    @Maurice Meyer 给出的答案的更新,允许提名班级成员:

    from functools import wraps
    
    def conditional_decorator(decoration, member):
        def decorator(method):
            predecorated = decoration(method)
            @wraps(method)
            def wrapper(*args, **kwargs):
                self = args[0]
                condition = getattr(self, member)
                if not condition:
                    return method(*args, **kwargs)
                return predecorated(*args, **kwargs)
             return wrapper
        return decorator
    
    #And used like this for example:
    class foo:
        def __init__(self, debug):
            self.debug = debug
    
        @conditional_decorator(decorator, "debug")
        def function(self):
            pass
    
    f1 = foo(True)
    f1.function()
    

    【讨论】:

      【解决方案3】:

      这是让装饰器处理类和参数的方式:

      from functools import wraps
      
      
      def conditional_decorator(param):
          def real_decorator(fn):
              @wraps(fn)
              def wrapper(*args, **kw):
                  cls = args[0]
                  print(cls.debug)
                  print(param)
              return wrapper
          return real_decorator
      
      
      class foo:
          def __init__(self):
              self.debug = True
      
          @conditional_decorator('param1')
          def function(self):
              pass
      
      
      
      f = foo()
      f.function()
      

      输出:

      True
      param1
      

      【讨论】:

        猜你喜欢
        • 2017-06-12
        • 2020-06-20
        • 2014-02-08
        • 1970-01-01
        • 1970-01-01
        • 2018-11-26
        • 1970-01-01
        • 2017-03-28
        • 2015-08-23
        相关资源
        最近更新 更多