python 的装饰器(Decorator)
Posted 小小喽啰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python 的装饰器(Decorator)相关的知识,希望对你有一定的参考价值。
先看一个例子
#这个是一个闭包,闭包前面已经说了 def log(func): def wrapper(*args, **kw): print(‘call %s():‘ % func.__name__) return func(*args, **kw) return wrapper @log def now(): print(‘2015-3-25‘) #调用函数 now() #输出 call now(): 2015-3-25
在我们调用这个函数的时候,第一件事并不是执行这个函数,而是将这个函数做为参数传入它头顶上这顶帽子,这顶帽子我们称之为装饰函数 或 装饰器,如上面的log()函数
装饰器的使用方法:
1.先定义一个装饰器(帽子),可以用类或者函数实现
2.再定义你的业务函数或者类
3.最后把帽子戴在这个函数头上
上面的例子log()函数是一个装饰器,返回的是一个函数,如果装饰器本身需要传入参数,则需要定义一个三层嵌套的函数
如:
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‘) #log函数传入参数‘execute‘ def now(): print(‘2015-3-25‘) now() #输出 execute now(): 2015-3-25
我们来剖析上面的语句,首先执行log(‘execute‘)
,返回的是decorator
函数,再调用返回的函数,参数是now
函数,返回值最终是wrapper
函数
使用funltools标准库中的wraps装饰器
#使用函数的属性__name__ now.__name__ #输出 ‘wrapper‘
函数对象有一个__name__
属性,可以拿到函数的名字,为啥返回值是wrapper,这是因为不管怎么嵌套,最终还是回到最里面那层,为了避免理解错误,就使用wraps装饰器
functools .wraps 装饰器,它的作用就是将 被修饰的函数(now) 的一些属性值赋值给 修饰器函数(log) ,最终让属性的显示更符合我们的直觉
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
wraps 其实是一个偏函数对象(partial),源码如下
def wraps(wrapped, assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES): return partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated)
练习:请设计一个decorator,它可作用于任何函数上,并打印该函数的执行时间:
import time, functools def metric(fn): @functools.wraps(fn) def wrapper(*args, **kw): start_time = time.time() e = fn(*args, **kw) end_time = time.time() print(‘%s executed in %s ms‘ % (fn.__name__, end_time-start_time)) return e return wrapper @metric def fast(x, y): time.sleep(0.0012) return x + y; @metric def slow(x, y, z): time.sleep(0.1234) return x * y * z; f = fast(11, 22) s = slow(11, 22, 33) if f != 33: print(‘测试失败!‘) elif s != 7986: print(‘测试失败!‘)
类的装饰器后面在聊
以上是关于python 的装饰器(Decorator)的主要内容,如果未能解决你的问题,请参考以下文章
python-闭包和装饰器-02-装饰器(decorator)