本隨筆是對Python札記 -- 裝飾器的一些補充。html
使用裝飾器的時候,被裝飾函數的一些屬性會丟失,好比以下代碼: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__
輸出以下:app
$ 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。示例代碼分別以下:post
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__屬性了。url
$ 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