- 增强
now()
函数的功能:在函数调用前后自动打印日志,但又不希望修改now()
函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator) - 本质上是一个返回函数的高阶函数
def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
使用:
@log#==>now=log(now)
def now():
print('2015-3-25')
输出:
>>> now()
call now():
2015-3-25
- 如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会更复杂
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
使用:
@log('execute')
def now():
print('2015-3-25')
输出:
>>> now()
execute now():
2015-3-25
- 两种decorator的定义都没有问题,还需要把原始函数的
__name__
等属性复制到wrapper()
函数中,否则,有些依赖函数签名的代码执行就会出错。
import functools
def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
import functools
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
练习
1.请设计一个decorator,它可作用于任何函数上,并打印该函数的执行时间:
def metric(func):
@functools.wraps(func)
def wraps(*args,**kw):
start=time.time()
res=func(*args,**kw)
end=time.time()
print("%s runned in %s seconds"%func.__name__,(end-start)*1000)
return res
return wraps
2.请编写一个decorator,能在函数调用的前后打印出'begin call'
和'end call'
的日志。
[https://blog.csdn.net/jiaowosiye/article/details/79272721]
def metric(func):
@functools.wraps(func)
def wrapper(*args,**kw):
print("begin call %s():"%func.__name__)//begin
res=func(*args,**kw)
print("the result of the program is {}".format(res))//获取输出
print("end call %s():"%func.__name__)//end
return res
return wrapper
3.思考一下能否写出一个@log
的decorator,使它既支持:
[https://blog.csdn.net/jiaowosiye/article/details/79272721]
@log
def f():
pass
又支持:
@log('execute')
def f():
pass
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args,**kw):
if text!=None:
print("the text is %s and the call %s(): "%(text,func.__name__))
res=func(*args,**kw)
return res
else: print("call %s ():"%func.__name__)
res=func(*args,**kw)
return res
return wrapper
if isinstance(text,str): #首先如果有参数 就跟原来一样直接返回decorator即可
return decorator
else: #如果没有参数 其实log(func)就是log里边其实直接传的参数就是func 返回的应该是wrapper
func=text
text=None
return decorator(func) #所以这里的应该是直接decorator(func) 返回wrapper