2.1.2.3 复制原始函数的文档字符串和其他属性
当修饰器返回一个新的函数来替代原始的函数时,一个不好的结果是原始的函数名、原始的文档字符串和原始参数列表都丢失了。通过设置doc(文档字符串)、module和name(完整的函数),以及annotations(关于参数和返回值的额外信息,在Python中可用)可以部分”移植“这些原始函数的属性到新函数的设定。这可以通过使用functools.update_wrapper来自动完成。
In [ ]:In [17]:
import functools
def better_replacing_decorator_with_args(arg):
print "defining the decorator"
def _decorator(function):
print "doing decoration,", arg
def _wrapper(*args, **kwargs):
print "inside wrapper,", args, kwargs
return function(*args, **kwargs)
return functools.update_wrapper(_wrapper, function)
return _decorator
@better_replacing_decorator_with_args("abc")
def function():
"extensive documentation"
print "inside function"
return 14
defining the decorator
doing decoration, abc
In [18]:
function
Out[18]:
<function __main__.function>
In [19]:
print function.__doc__
extensive documentation
在属性列表中缺少了一个重要的东西:参数列表,这些属性可以复制到替换的函数。参数的默认值可以用defaults
、kwdefaults
属性来修改,但是,不幸的是参数列表本身不能设置为属性。这意味着help(function)
将显示无用的参数列表,对于函数用户造成困扰。一种绕过这个问题的有效但丑陋的方法是使用eval
来动态创建一个封装器。使用外部的decorator
模块可以自动完成这个过程。它提供了对decorator
装饰器的支持,给定一个封装器将它转变成保留函数签名的装饰器。
总结一下,装饰器通常应该用functools.update_wrapper
或其他方式来复制函数属性。