Python札记 -- 装饰器补充

    本随笔是对Python札记 -- 装饰器的一些补充。

    使用装饰器的时候,被装饰函数的一些属性会丢失,比如如下代码:

 1 #!/usr/bin/env python

 2 

 3 def deco(func):

 4     def wrapper():

 5         print "Wrap start"

 6         func()

 7         print "Wrap end\n"

 8     return wrapper

 9 

10 @deco

11 def foo():

12     """Docstring for foo"""

13     print "In foo():"

14 

15 foo()

16 print foo.__name__

17 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。示例代码分别如下:

 1 #!/usr/bin/env python

 2 from functools import update_wrapper

 3 

 4 def deco(func):

 5     def wrapper():

 6         print "Wrap start"

 7         func()

 8         print "Wrap end\n"

 9     return update_wrapper(wrapper,func) #调用update_wrapper方法

10 

11 @deco

12 def foo():

13     """Docstring for foo"""

14     print "In foo():"

15 

16 foo()

17 print foo.__name__

18 print foo.__doc__
 1 #!/usr/bin/env python

 2 from functools import wraps

 3 

 4 def deco(func):

 5     @wraps(func) #使用装饰器来实现

 6     def wrapper():

 7         print "Wrap start"

 8         func()

 9         print "Wrap end\n"

10     return wrapper

11 

12 @deco

13 def foo():

14     """Docstring for foo"""

15     print "In foo():"

16 

17 foo()

18 print foo.__name__

19 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)