如何在python中使用条件装饰器?
Posted
技术标签:
【中文标题】如何在python中使用条件装饰器?【英文标题】:How to use a conditional decorator in python? 【发布时间】:2019-03-03 09:18:14 【问题描述】:在尝试理解 python 中的条件装饰器时,我遇到了this example。该问题的公认答案解释了如何定义条件装饰器,而不是如何使用它。
示例代码如下:
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)
@conditional_decorator(timeit, doing_performance_analysis)
def foo():
time.sleep(2)
但是如何使用它呢?我尝试了以下foo
的调用,如下所示:
doing_performance_analysis=False
foo()
doing_performance_analysis=True
foo()
但我收到以下错误:
Traceback (most recent call last):
File "tester.py", line 18, in <module>
@conditional_decorator(timeit, doing_performance_analysis)
NameError: name 'doing_performance_analysis' is not defined
那么它是如何正常工作的呢?
【问题讨论】:
正如 Martijn 在他的 cmets 中所说的那样,这只是有条件的,因为它是在 import 时间进行评估的。您不能在调用时更改它。 你得到的错误告诉你你没有设置名字doing_performance_analysis
。您是否尝试过将该名称定义为布尔值?
我想我已经将该名称设置为布尔值,请参阅我的问题。我不确定你的意思是什么......
您需要在应用装饰器时设置它。这就是为什么@conditional_decorator()
行出现错误的原因。
所以当我需要在开头设置名称时,我根本没有条件装饰器,而是静态的,不可更改的装饰器......
【参考方案1】:
您可以将 condition
改为一个函数,并让装饰器返回一个函数包装器,以便它在运行时评估您想要的设置变量。
from functools import wraps
class conditional_decorator(object):
def __init__(self, dec, predicate):
self.decorator = dec
self.predicate = predicate
def __call__(self, func):
decorated_func = self.decorator(func)
@wraps(func)
def wrapper(*args, **kwargs):
if self.predicate():
return decorated_func(*args, **kwargs)
return func(*args, **kwargs)
return wrapper
@conditional_decorator(timeit, lambda: doing_performance_analysis)
def foo():
time.sleep(2)
这样就可以按您的意愿工作:
doing_performance_analysis=False
foo()
doing_performance_analysis=True
foo()
【讨论】:
对我来说似乎不对......它在定义foo
时评估条件,而不是在您评估 foo()
时评估条件
确实如此。现在修好了。谢谢。
我很想只装饰一次函数,每次调用都装饰它似乎有点浪费【参考方案2】:
如果你使用 python 3 wrapt 模块,你可以设置一个启用标志来打开或关闭你的装饰器。出于调试原因,我尝试将给定函数的特定参数粘贴到剪贴板(使用熊猫)。这是由以下装饰器完成的。
CLIPTRACE = True
def traceClipboard(fieldname):
""" give fieldname of the functions formal parameter
to get value dumped to clipboard
also use wrapt parameter to disable if cliptrace is not set
"""
@wrapt.decorator(enabled=CLIPTRACE)
def wrapper(wrapped, instance, args, kwargs):
args_list = inspect.getfullargspec(wrapped)[0]
if "self" in args_list:
args_list.pop(0)
if fieldname in args_list:
pyperclip.copy(args[args_list.index(fieldname)])
if fieldname in kwargs.keys():
pyperclip.copy(kwargs.get(fieldname))
return wrapped(*args, **kwargs)
return wrapper
然后用它来装饰我的会话类的功能:
@traceClipboard("url")
def _get(self, url, odata=None):
"""single _get request..."""
只要 CLIPTRACE 为 True,参数“url”的值就会被复制到剪贴板,在生产环境中 CLIPTRACE 为 False,不会执行剪贴板复制。
【讨论】:
以上是关于如何在python中使用条件装饰器?的主要内容,如果未能解决你的问题,请参考以下文章