1 # -*- coding: utf-8 -*- 2 3 def log(func): 4 def wrapper(*args,**kwargs): 5 print('这个函数是 %s()'%func.__name__) 6 return func(*args,**kwargs) 7 8 return wrapper 9 # import functools10 # def log(text):11 # def decorator(func):12 # @functools.wraps(func)13 # def wrapper(*args, **kw):14 # #wrapper.__name__ = func.__name__15 # print('%s 这个函数是 %s():' % (text, func.__name__))16 # 17 # return func(*args, **kw)18 # return wrapper19 # return decorator20 21 # @log('hello') #now=log('hello')(now)22 @log23 def now():24 print('2018-06-30')25 return 126 27 print(now())28 print(now.__name__)
结果:
这个函数是 now()2018-06-301wrapper
以上两种decorator的定义都没有问题,但还差最后一步。因为我们讲了函数也是对象,它有__name__
等属性,但你去看经过decorator装饰之后的函数,它们的__name__
已经从原来的'now'
变成了'wrapper'
:
因为返回的那个wrapper()
函数名字就是'wrapper'
,所以,需要把原始函数的__name__
等属性复制到wrapper()
函数中,否则,有些依赖函数签名的代码执行就会出错。
# -*- coding: utf-8 -*-def log(func): def wrapper(*args,**kwargs): wrapper.__name__ = func.__name__ print('这个函数是 %s()'%func.__name__) return func(*args,**kwargs) return wrapper@logdef now(): print('2018-06-30') return 1 print(now())print(now.__name__)
结果:
这个函数是 now()2018-06-301now
不需要编写wrapper.__name__ = func.__name__
这样的代码,Python内置的functools.wraps
就是干这个事的,所以,一个完整的decorator的写法如下:
1 # -*- coding: utf-8 -*- 2 import functools 3 def log(func): 4 @functools.wraps(func) 5 def wrapper(*args,**kwargs): 6 # wrapper.__name__ = func.__name__ 7 print('这个函数是 %s()'%func.__name__) 8 return func(*args,**kwargs) 9 10 return wrapper11 12 @log13 def now():14 print('2018-06-30')15 return 116 17 print(now())18 print(now.__name__)
结果:
这个函数是 now()2018-06-301now
import functools
是导入functools
模块。模块的概念稍候讲解。现在,只需记住在定义wrapper()
的前面加上@functools.wraps(func)
即可。