本随笔是对Python札记 -- 装饰器的一些补充。
使用装饰器的时候,被装饰函数的一些属性会丢失,比如如下代码:
1#!/usr/bin/env python23defdeco(func):4defwrapper():5PRint"Wrap start"6func()7print"Wrap end\n"8returnwrapper910@deco11deffoo():12"""Docstring for foo"""13print"In foo():"1415foo()16printfoo.__name__17printfoo.__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。示例代码分别如下:
1#!/usr/bin/env python2fromfunctoolsimportupdate_wrapper34defdeco(func):5defwrapper():6print"Wrap start"7func()8print"Wrap end\n"9returnupdate_wrapper(wrapper,func)#调用update_wrapper方法1011@deco12deffoo():13"""Docstring for foo"""14print"In foo():"1516foo()17printfoo.__name__18printfoo.__doc__
1#!/usr/bin/env python2fromfunctoolsimportwraps34defdeco(func):5@wraps(func)#使用装饰器来实现6defwrapper():7print"Wrap start"8func()9print"Wrap end\n"10returnwrapper1112@deco13deffoo():14"""Docstring for foo"""15print"In foo():"1617foo()18printfoo.__name__19printfoo.__doc__
现在被deco装饰过的foo方法,可以保留之前的__name__和__doc__属性了。
$ python decorator_test_with_update_wrapper.py
Wrap start
In foo():
Wrap end
foo
Docstringforfoo
$ python decorator_test_with_wraps.py
Wrap start
In foo():
Wrap end
foo
Docstringforfoo