<p>我知道这个问题已经过时了,但有些评论是新的,虽然所有可行的解决方案基本上都是一样的,但大多数都不是很干净,也不容易阅读。</p>
<p>正如thobe的回答所说,处理这两种情况的唯一方法是检查两种情况。最简单的方法是简单地检查是否有一个参数并且它是callabe(注意:如果您的decorator只接受一个参数并且它恰好是一个可调用的对象,则需要额外的检查):</p>
<pre><code>def decorator(*args, **kwargs):
if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
# called as @decorator
else:
# called as @decorator(*args, **kwargs)
</code></pre>
<p>在第一种情况下,您可以像任何普通的decorator那样,返回传入函数的修改或包装版本。</p>
<p>在第二种情况下,返回一个“new”装饰器,它以某种方式使用了用*args,**kwargs传入的信息。</p>
<p>这是很好的,所有,但必须写出来的每一个装饰你可以很烦人,而不是干净。相反,它将是很好的,能够自动修改我们的装饰,而不必重新编写他们。。。但这就是装饰师的职责!</p>
<p>使用下面的decorator decorator,我们可以对decorator进行deocrate,以便它们可以在有或无参数的情况下使用:</p>
<pre><code>def doublewrap(f):
'''
a decorator decorator, allowing the decorator to be used as:
@decorator(with, arguments, and=kwargs)
or
@decorator
'''
@wraps(f)
def new_dec(*args, **kwargs):
if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
# actual decorated function
return f(args[0])
else:
# decorator arguments
return lambda realf: f(realf, *args, **kwargs)
return new_dec
</code></pre>
<p>现在,我们可以用@doublewrap来装饰我们的装饰人员,他们将在有无争论的情况下工作,但有一个警告:</p>
<p>我在上面提到过,但这里应该重复一次,这个decorator中的check对decorator可以接收的参数做了一个假设(即它不能接收一个可调用的参数)。由于我们现在正在使它适用于任何发电机,它需要记住,或修改,如果它将矛盾。</p>
<p>以下说明其用途:</p>
<pre><code>def test_doublewrap():
from util import doublewrap
from functools import wraps
@doublewrap
def mult(f, factor=2):
'''multiply a function's return value'''
@wraps(f)
def wrap(*args, **kwargs):
return factor*f(*args,**kwargs)
return wrap
# try normal
@mult
def f(x, y):
return x + y
# try args
@mult(3)
def f2(x, y):
return x*y
# try kwargs
@mult(factor=5)
def f3(x, y):
return x - y
assert f(2,3) == 10
assert f2(2,5) == 30
assert f3(8,1) == 5*7
</code></pre>