标签:嵌套 函数 turn 调用 now() ret too begin 日志
装饰器就是返回函数的实际运用,装饰器接受一个原函数作为参数,返回值是一个现函数,调用装饰器就可以在原函数调用前后进行操作,而不改变原函数。
def now():
print(‘2015-3-25‘)
def log(func):
def wrapper(*args, **kw):
print(‘call %s():‘ % func.__name__)
return func(*args, **kw)
return wrapper
log(now)()
以上述代码为例,now为原函数,log为装饰器,log接受函数func作为输入参数,返回wrapper函数作为返回值,而wrapper函数在func函数调用前打印日志,wrapper函数可以接受任意参数的调用,代表原始函数的参数可以是任意形式的。
最后的log(now)先返回wrapper,然后log(now)()就调用了wrapper(),而wrapper()首先打印了日志,然后返回了func(),而func()就是now()。
也可以使用@log对now重新定义,这样now就是一个装饰器
@log
def now():
print(‘2015-3-25‘)
这样就相当于运行了now=log(now),因此直接运行now()就达到了上面的效果,但是now函数名指向的函数定义变化了。
如果装饰器本身需要输入参数,由于装饰器只能接受函数作为参数,所以又要在装饰器外面再套一层高阶函数,传入所需的参数,将装饰器函数作为最终的返回值返回
如下所示:
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(‘想要打印的日志‘)(now)(),也可以在原函数定义前加@log(‘想要打印的日志‘)
如果使用了装饰器重新定义函数,那么它的__name__等属性就变为了wrapper,因此需要在装饰器定义前加上@functools.wraps(func)
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(args):
if isinstance(args,str):
def dec(func):
@functools.wraps(func)
def wrapper(*a,**kw):
print(‘begin func‘,args)
func(*a,**kw)
print(‘end func‘)
return wrapper
return dec
else:
@functools.wraps(args)
def wrapper(*a, **kw):
print(‘begin func‘, args)
args(*a, **kw)
print(‘end func‘)
return wrapper
@log(‘execute‘)
def f():
print(‘I am here‘)
@log
def f():
print(‘I am here‘)
f()
@log
def f():
pass
等价于 f=log(f)
@log(‘execute‘)
def f():
pass
等价于f=log(‘execute‘)(f)
解法中根据log()括号中的参数类型是否为字符串来判断,如果参数为字符串,那么属于三层嵌套的装饰器,如果参数不是字符串,那么就将args作为被调用的函数名参数,即两层嵌套。
课外阅读:
http://www.cnblogs.com/myd7349/p/how_to_use_wraps_of_functools.html
标签:嵌套 函数 turn 调用 now() ret too begin 日志
原文地址:http://www.cnblogs.com/vonkimi/p/6901693.html