切换装饰器

eng*_*erC 8 python decorator

什么是打开和关闭装饰器的最佳方法,而不是实际去每个装饰并将其评论出来?假设您有一个基准测试装饰器:

# deco.py
def benchmark(func):
  def decorator():
    # fancy benchmarking 
  return decorator
Run Code Online (Sandbox Code Playgroud)

在你的模块中,例如:

# mymodule.py
from deco import benchmark

class foo(object):
  @benchmark
  def f():
    # code

  @benchmark
  def g():
    # more code
Run Code Online (Sandbox Code Playgroud)

这很好,但有时你不关心基准测试,也不想要开销.我一直在做以下事情.添加另一个装饰者:

# anothermodule.py
def noop(func):
  # do nothing, just return the original function
  return func
Run Code Online (Sandbox Code Playgroud)

然后注释掉导入行并添加另一行:

# mymodule.py
#from deco import benchmark 
from anothermodule import noop as benchmark
Run Code Online (Sandbox Code Playgroud)

现在,基于每个文件切换基准测试,只需要更改相关模块中的import语句.可以独立控制各个装饰器.

有一个更好的方法吗?最好不要编辑源文件,并指定在其他地方使用哪些文件的装饰器.

nne*_*neo 5

您可以将条件添加到装饰器本身:

def benchmark(func):
    if not <config.use_benchmark>:
        return func
    def decorator():
    # fancy benchmarking 
    return decorator
Run Code Online (Sandbox Code Playgroud)

  • 这不允许按文件切换,并且如果装饰器来自标准库或无法编辑,则必须在每个装饰器的包装器中完成。 (2认同)

小智 5

我一直在使用以下方法。它与 CaptainMurphy 建议的几乎相同,但它的优点是您不需要像函数一样调用装饰器。

import functools

class SwitchedDecorator:
    def __init__(self, enabled_func):
        self._enabled = False
        self._enabled_func = enabled_func

    @property
    def enabled(self):
        return self._enabled

    @enabled.setter
    def enabled(self, new_value):
        if not isinstance(new_value, bool):
            raise ValueError("enabled can only be set to a boolean value")
        self._enabled = new_value

    def __call__(self, target):
        if self._enabled:
            return self._enabled_func(target)
        return target


def deco_func(target):
    """This is the actual decorator function.  It's written just like any other decorator."""
    def g(*args,**kwargs):
        print("your function has been wrapped")
        return target(*args,**kwargs)
    functools.update_wrapper(g, target)
    return g


# This is where we wrap our decorator in the SwitchedDecorator class.
my_decorator = SwitchedDecorator(deco_func)

# Now my_decorator functions just like the deco_func decorator,
# EXCEPT that we can turn it on and off.
my_decorator.enabled=True

@my_decorator
def example1():
    print("example1 function")

# we'll now disable my_decorator.  Any subsequent uses will not
# actually decorate the target function.
my_decorator.enabled=False
@my_decorator
def example2():
    print("example2 function")
Run Code Online (Sandbox Code Playgroud)

在上面,example1 将被修饰,example2 将不会被修饰。当我必须按模块启用或禁用装饰器时,只要我需要不同的副本,我只需创建一个新的 SwitchedDecorator 函数。