装饰器的主要功能:在不改变函数调用方式的基础上在函数的前、后添加功能 ,类似C#的AOP编程。添加功能的这部分就在装饰器中,典型的格式如下:
def timer(func): def inner(*args,**kwargs): '''执行函数之前要做的''' re = func(*args,**kwargs) '''执行函数之后要做的''' return re return inner from functools import wraps def deco(func): @wraps(func) #加在最内层函数正上方 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper
比如我们给fun增加一个记时的装饰器,还要考虑到函数的参数调用
import time def timer(f): # 装饰器函数 def inner(*argc, **kwargc): start = time.time() ret = f(*argc, **kwargc) # 被装饰的函数 end = time.time() print(end - start) return ret return inner @timer # 语法糖 @装饰器函数名,相当于调用func=timmer(func) def func(name): # 紧挨着被装饰函数 time.sleep(0.01) print("hello:%s" % name) return "first time:"+name
运行结果如下:
hello:gavin
0.010966062545776367
first time:gavin
两个有用的宏:fun的__name__查看字符串格式的函数名,__doc__查看函数的注释
from functools import wraps def wrapper(func): #func = holiday @wraps(func) def inner(*args,**kwargs): print('在被装饰的函数执行之前做的事') ret = func(*args, **kwargs) print('在被装饰的函数执行之后做的事') return ret return inner @wrapper #holiday = wrapper(holiday) def holiday(day): '''这是一个放假通知''' print('全体放假%s天'%day) return '好开心' print(holiday.__name__) print(holiday.__doc__) ret = holiday(3) #inner print(ret)
运行结果:
holiday
这是一个放假通知
在被装饰的函数执行之前做的事
全体放假3天
在被装饰的函数执行之后做的事
好开心
带参数的装饰器:假如你有成千上万个函数使用了一个装饰器,现在你想把这些装饰器都取消掉,你要怎么做?一个一个的取消掉?
import time FLAGE = False def timmer_out(flag): def timmer(func): def inner(*args, **kwargs): if flag: start = time.time() ret = func(*args, **kwargs) end = time.time() print(end-start) return ret else: ret = func(*args, **kwargs) return ret return inner return timmer # timmer = timmer_out(FLAGE) @timmer_out(FLAGE) #wahaha = timmer(wahaha) def wahaha(): time.sleep(0.1) print('wahahahahahaha') @timmer_out(True) def erguotou(): time.sleep(0.1) print('erguotoutoutou') wahaha() erguotou()
运行结果:
wahahahahahaha
erguotoutoutou
0.10001111030578613
多个装饰器装饰同一个函数:
def wrapper1(func): def inner1(): print('wrapper1 ,before func') ret = func() print('wrapper1 ,after func') return ret return inner1 def wrapper2(func): def inner2(): print('wrapper2 ,before func') ret = func() print('wrapper2 ,after func') return ret return inner2 def wrapper3(func): def inner3(): print('wrapper3 ,before func') ret = func() print('wrapper3 ,after func') return ret return inner3 @wrapper3 @wrapper2 @wrapper1 def f(): print('in f') return '哈哈哈' print(f())
运行结果:
wrapper3 ,before func
wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func
wrapper3 ,after func
哈哈哈
functools的wrap:Python装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),为了不影响,Python的functools包中提供了一个叫wraps的decorator来消除这样的副作用。写一个decorator的时候,最好在实现之前加上functools的wrap,它能保留原有函数的名称和docstring。
不加wraps:
# coding=utf-8 # -*- coding=utf-8 -*- from functools import wraps def my_decorator(func): def wrapper(*args, **kwargs): '''decorator''' print('Calling decorated function...') return func(*args, **kwargs) return wrapper @my_decorator def example(): """Docstring""" print('Called example function') print(example.__name__, example.__doc__)
运行结果是:
wrapper decorator
返回的值装饰器的名称和注释;加wraps:
# coding=utf-8 # -*- coding=utf-8 -*- from functools import wraps def my_decorator(func): @wraps(func) def wrapper(*args, **kwargs): '''decorator''' print('Calling decorated function...') return func(*args, **kwargs) return wrapper @my_decorator def example(): """Docstring""" print('Called example function') print(example.__name__, example.__doc__)
运行结果:
example Docstring
是源函数的定义和注释