好吧,为了简化它,让我们首先处理函数。假设您有一个函数可以打印有关其参数的内容:
def print_info(breed, name):
print "The doggie %s's breed is %s." % (name, breed)
像这样:
>>> print_info("Labrador", "Spike")
The doggie Spike's breed is Labrador.
>>> print_info("Pit Bull", "Spot")
The doggie Spot's breed is Pit Bull.
现在您希望该函数始终小写品种。因此,以一种理智的方式,您只需这样做:
def manually_lowered_print_info(breed, name):
print "The doggie %s's breed is %s." % (name, breed.lower())
输出是:
>>> manually_lowered_print_info("Labrador", "Spike")
The doggie Spike's breed is labrador.
但是假设由于某种原因,您经常不得不将您编写的函数的第一个字符串参数小写,因此您想将其抽象为装饰器。我们希望它看起来像这样并具有相同的输出:
@lower_first_arg
def dec_lowered_print_info(breed, name):
print "The doggie %s's breed is %s." % (name, breed)
这只是语法糖:
def tmp_func(breed, name):
print "The doggie %s's breed is %s." % (name, breed)
dec_lowered_print_info = lower_first_arg(tmp_func)
所以我们要lower_first_arg
返回转换后的print_info
函数。我们先做一个专门为函数量身定做的print_info
函数。
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
它有效吗?让我们来看看:
>>> 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.
伟大的!请注意,我们将print_info
作为参数传递给lower_first_arg
函数,在那里它被局部变量引用print_info_func_arg
。
如果我们使用装饰器语法,它的工作原理是一样的:
@lower_first_arg
def dec_lowered_print_info(breed, name):
print "The doggie %s's breed is %s." % (name, breed)
杰出的:
>>> dec_lowered_print_info("Pit Bull", "Spot")
The doggie Spot's breed is pit bull.
酷,就是这样,真的。现在为了让装饰器更通用,让我们先概括一下名称:
def generic_lower_first_arg(f):
def wrapped(arg1, arg2):
return f(arg1.lower(), arg2)
return wrapped
现在这里的问题是这个装饰器只适用于 2 个参数的函数。理想情况下,我们希望它适用于 1 arg 或更多的任何函数,例如:
@generic_lower_first_arg
def failed_whatnow(first, last, middle):
print "%s %s %s" % (first, middle, last)
现在,该代码将运行,但如果我们尝试调用它,则会出现错误:
>>> 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)
这是怎么回事?好吧,装饰器接受failed_whatnow
并返回了它定义的函数wrapped
,但该wrapped
函数只接受两个参数!这里的修复是使用可变参数语法。传递可能提供给包装函数的任何关键字参数通常也是一个好主意。
def proper_lower_first_arg(f):
def wrapped(arg1, *args, **kwargs):
return f(arg1.lower(), *args, **kwargs)
return wrapped
现在它适用于各种功能:
@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
证明:
>>> 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!'