如何在python中做一个条件装饰器

cfp*_*ete 24 python conditional decorator python-decorators

是否有可能有条件地装饰一个功能.例如,我想foo()用timer函数装饰函数(timeit)只有doing_performance_analysis True(参见下面的伪代码).

if doing_performance_analysis:
  @timeit
  def foo():
    """
    do something, timeit function will return the time it takes
    """
    time.sleep(2)
else:
  def foo():
    time.sleep(2)  
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 39

装饰器只是返回替换,可选择相同功能,包装器或完全不同的东西的callables.因此,您可以创建条件装饰器:

def conditional_decorator(dec, condition):
    def decorator(func):
        if not condition:
            # Return the function unchanged, not decorated.
            return func
        return dec(func)
    return decorator
Run Code Online (Sandbox Code Playgroud)

现在您可以像这样使用它:

@conditional_decorator(timeit, doing_performance_analysis)
def foo():
    time.sleep(2)  
Run Code Online (Sandbox Code Playgroud)

装饰者也可以是一个类:

class conditional_decorator(object):
    def __init__(self, dec, condition):
        self.decorator = dec
        self.condition = condition

    def __call__(self, func):
        if not self.condition:
            # Return the function unchanged, not decorated.
            return func
        return self.decorator(func)
Run Code Online (Sandbox Code Playgroud)

这里的__call__方法decorator()与第一个示例中返回的嵌套函数扮演相同的角色,此处的closed-over decconditionparameters作为参数存储在实例中,直到应用了decorator.

  • 装饰器在导入时应用,因此当时不会查询实例变量.你必须为此编写一个不同的装饰器,一个在调用时检查自己的装饰器.超出此Q和评论格式的范围.:-) (2认同)

Blc*_*ght 10

装饰器只是应用于另一个功能的函数.您可以手动应用它:

def foo():
   # whatever
   time.sleep(2)

if doing_performance_analysis:
    foo = timeit(foo)
Run Code Online (Sandbox Code Playgroud)


NPE*_*NPE 5

怎么样:

def foo():
   ...

if doing_performance_analysis:
   foo = timeit(foo)
Run Code Online (Sandbox Code Playgroud)

我想您甚至可以将其包装到一个带有布尔值标志的装饰器和另一个装饰器中,并且仅当将标志设置为时才应用后者True

def cond_decorator(flag, dec):
   def decorate(fn):
      return dec(fn) if flag else fn
   return decorate

@cond_decorator(doing_performance_analysis, timeit)
def foo():
   ...
Run Code Online (Sandbox Code Playgroud)