<p>为了简化它,我们先来处理函数。假设您有一个函数,它可以打印其参数的某些信息:</p>
<pre><code>def print_info(breed, name):
print "The doggie %s's breed is %s." % (name, breed)
</code></pre>
<p>因此:</p>
^{pr2}$
<p>现在你希望这个函数总是小写。所以你应该理智地这样做:</p>
<pre><code>def manually_lowered_print_info(breed, name):
print "The doggie %s's breed is %s." % (name, breed.lower())
</code></pre>
<p>输出为:</p>
<pre><code>>>> manually_lowered_print_info("Labrador", "Spike")
The doggie Spike's breed is labrador.
</code></pre>
<p>但是,假设由于某种原因,您经常需要将您编写的函数的第一个字符串参数小写,所以您想将其抽象为decorator。我们希望它看起来像这样并且有相同的输出:</p>
<pre><code>@lower_first_arg
def dec_lowered_print_info(breed, name):
print "The doggie %s's breed is %s." % (name, breed)
</code></pre>
<p>这只是语法上的甜点:</p>
<pre><code>def tmp_func(breed, name):
print "The doggie %s's breed is %s." % (name, breed)
dec_lowered_print_info = lower_first_arg(tmp_func)
</code></pre>
<p>{{we要返回<cdm><eem}。让我们首先为<code>print_info</code>函数专门定制一个函数。在</p>
<pre><code>def lower_first_arg(print_info_func_arg):
def inner_print_info(breed, name):
return print_info_func_arg(breed.lower(), name)
return inner_print_info
</code></pre>
<p>有用吗?让我们看看:</p>
<pre><code>>>> transformed_print_info = lower_first_arg(print_info)
>>> print_info("Pit Bull", "Spot")
The doggie Spot's breed is Pit Bull.
>>> transformed_print_info("Pit Bull", "Spot")
The doggie Spot's breed is pit bull.
</code></pre>
太好了!请注意,我们将<code>print_info</code>作为参数传递给<code>lower_first_arg</code>函数,在该函数中,它由局部变量<code>print_info_func_arg</code>引用。在</p>
<p>如果我们使用decorator语法,它的工作原理是相同的:</p>
<pre><code>@lower_first_arg
def dec_lowered_print_info(breed, name):
print "The doggie %s's breed is %s." % (name, breed)
</code></pre>
<p>杰出的:</p>
<pre><code>>>> dec_lowered_print_info("Pit Bull", "Spot")
The doggie Spot's breed is pit bull.
</code></pre>
<hr/>
<p>很酷,就这样,真的。现在为了使decorator更通用,让我们首先概括一下这些名称:</p>
<pre><code>def generic_lower_first_arg(f):
def wrapped(arg1, arg2):
return f(arg1.lower(), arg2)
return wrapped
</code></pre>
<p>现在的问题是这个decorator只对2个arg的函数起作用。理想情况下,我们希望它能在任何1 arg或更多的函数上工作,例如:</p>
<pre><code>@generic_lower_first_arg
def failed_whatnow(first, last, middle):
print "%s %s %s" % (first, middle, last)
</code></pre>
<p>现在,该代码将运行,但如果尝试调用它,则会出现错误:</p>
<pre><code>>>> failed_whatnow("Bob", "Jones", "The Killer")
Traceback (most recent call last):
File "<pyshell#26>", line 1, in <module>
failed_whatnow("Bob", "Jones", "The Killer")
TypeError: wrapped() takes exactly 2 arguments (3 given)
</code></pre>
<p>怎么回事?好吧,decorator接受<code>failed_whatnow</code>并返回它定义的函数<code>wrapped</code>,但是{<cd8>}函数只接受两个参数!这里的修复方法是使用varargs语法。通常,传递给包装函数的任何关键字参数也是一个好主意。在</p>
<pre><code>def proper_lower_first_arg(f):
def wrapped(arg1, *args, **kwargs):
return f(arg1.lower(), *args, **kwargs)
return wrapped
</code></pre>
<p>现在它可以处理各种功能:</p>
<pre><code>@proper_lower_first_arg
def proper_whatnow(first, last, middle):
print "%s %s %s" % (first, middle, last)
@proper_lower_first_arg
def multiplyit(mm, n=3):
return mm * n
</code></pre>
<p>证明:</p>
<pre><code>>>> proper_whatnow("Bob", "Jones", "The Killer")
bob The Killer Jones
>>> multiplyit("HaHa.Fool!")
'haha.fool!haha.fool!haha.fool!'
>>> multiplyit("HaHa.Fool!", n=5)
'haha.fool!haha.fool!haha.fool!haha.fool!haha.fool!'
</code></pre>