本随笔是对Python札记 -- 装饰器的一些补充。
使用装饰器的时候,被装饰函数的一些属性会丢失,比如如下代码:
#!/usr/bin/env python def deco(func): def wrapper(): print "Wrap start" func() print "Wrap end\n" return wrapper @deco def foo(): """Docstring for foo""" print "In foo():" foo() print foo.__name__ print foo.__doc__
输出如下:
$ python decorator_test.py Wrap start In foo(): Wrap end wrapper None
可以发现,__name__属性成了wrapper,而__doc__属性则成了None。这对于平常使用多少带来些不便,总不能给每个使用装饰器的函数都重写__name__和__doc__吧。
Python的functools提供的update_wrapper和wraps可以有效解决这个问题。不过update_wrapper是用方法的形式进行调用,而wraps则是用装饰器来封装了update_wrapper。示例代码分别如下:
decorator_test_with_update_wrapper.py
#!/usr/bin/env python
from functools import update_wrapper
def deco(func):
def wrapper():
print "Wrap start"
func()
print "Wrap end\n"
return update_wrapper(wrapper,func) #调用update_wrapper方法
@deco
def foo():
"""Docstring for foo"""
print "In foo():"
foo()
print foo.__name__
print foo.__doc__
decorator_test_with_wraps.py
#!/usr/bin/env python
from functools import wraps
def deco(func):
@wraps(func) #使用装饰器来实现
def wrapper():
print "Wrap start"
func()
print "Wrap end\n"
return wrapper
@deco
def foo():
"""Docstring for foo"""
print "In foo():"
foo()
print foo.__name__
print foo.__doc__
现在被deco装饰过的foo方法,可以保留之前的__name__和__doc__属性了。
$ python decorator_test_with_update_wrapper.py Wrap start In foo(): Wrap end foo Docstring for foo $ python decorator_test_with_wraps.py Wrap start In foo(): Wrap end foo Docstring for foo

本文深入探讨了Python装饰器的基本概念及其使用过程中出现的问题,特别是装饰器对被装饰函数属性的影响,并通过functools中的update_wrapper和wraps方法解决了这一问题。详细展示了如何在不修改原有函数的情况下保留其名称和文档字符串,同时提供了具体的示例代码以供参考。

被折叠的 条评论
为什么被折叠?



