<p>通过这里和其他地方的答案的帮助和一系列的尝试和错误,我发现实际上有一种更简单和通用的方法可以让decorator接受可选参数。它确实检查了用它调用的args,但没有其他方法可以这样做。</p>
<p>关键是要装饰你的装饰师。</p>
<h2>泛型decorator decorator代码</h2>
<p>这里是decorator decorator(此代码是通用的,任何需要可选arg decorator的人都可以使用)</strong>:</p>
<pre><code>def optional_arg_decorator(fn):
def wrapped_decorator(*args):
if len(args) == 1 and callable(args[0]):
return fn(args[0])
else:
def real_decorator(decoratee):
return fn(decoratee, *args)
return real_decorator
return wrapped_decorator
</code></pre>
<h2>用法</h2>
<p>使用它就像:</p>
<ol>
<li>像平常一样创建一个装饰器。</li>
<li>在第一个目标函数参数之后,添加可选参数。</li>
<li>用<code>optional_arg_decorator</code>装饰装饰器</li>
</ol>
<p>示例:</p>
<pre><code>@optional_arg_decorator
def example_decorator_with_args(fn, optional_arg = 'Default Value'):
...
return fn
</code></pre>
<h2>测试用例</h2>
<h2>对于您的用例:</h2>
<p>因此,对于您的情况,使用传入的方法名或<code>__name__</code>(如果<em>None</em>)保存函数的属性:</p>
<pre><code>@optional_arg_decorator
def register_method(fn, method_name = None):
fn.gw_method = method_name or fn.__name__
return fn
</code></pre>
<h2>添加修饰方法</h2>
<p>现在您有了一个带或不带参数的装饰器:</p>
<pre><code>@register_method('Custom Name')
def custom_name():
pass
@register_method
def default_name():
pass
assert custom_name.gw_method == 'Custom Name'
assert default_name.gw_method == 'default_name'
print 'Test passes :)'
</code></pre>