如果您希望装饰器接受参数,那么使用基于类的装饰器是一种方法。根据我的经验,他们最终能够更轻松地进行推理和维护。它们很简单,__init__
接受装饰器的任何参数,__call__
返回装饰函数。其中一个写装饰器的问题是如果它们传递参数或者不参与,它们的行为完全不同。这是很容易在基于类的装饰,以解决这个问题,让你的装饰,以接受参数或不:
class target:
def __init__(self, targets):
"""Arguments for decorator"""
self.targets = None
if not hasattr(targets, '__call__'):
# check we are actually passed arguments!
# if targets has __call__ attr, we were called w/o arguments
self.targets = targets
def __call__(self, f):
"""Returns decorated function"""
if self.targets:
def newf(*args, **kwargs):
for target in self.targets:
f(target)
return newf
else:
return f
现在,如果我们使用参数的装饰,它会按预期工作,调用我们的函数3倍:
>>> @target([1,2,3])
..: def foo(x): print x
...
>>> foo()
1
2
3
但是,如果我们不带参数调用,我们将返回,而不是原来的功能:
>>> @target
def foo(x): print x
..:
>>> foo(3)
<<< 3
伟大的答案,但我发现基于类的装饰更容易使用我的工作n装饰者接受参数/战士的情况。 – zeekay 2011-05-09 18:58:59
感谢您的想法。 – ycseattle 2011-05-09 21:34:45
我和OP有相同的需求。但是你的建议并不适合我。我遇到的第一个问题是解决方案相当简单。装饰器需要应用于一个方法,但你的答案中的“装饰器”不需要“自我”参数。另一个问题似乎更成问题。测试运行者将在循环之外调用适当的设置和清理方法。这意味着状态不会在测试用例之间得到清理,就像使用两个单独的'test_'函数一样。这会导致测试用例失败。 – kasperd 2014-12-16 14:05:34