装饰器的主要功能:在不改变函数调用方式的基础上在函数的前、后添加功能 ,相似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增长一个记时的装饰器,还要考虑到函数的参数调用app
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:gavinspa
两个有用的宏:fun的__name__查看字符串格式的函数名,__doc__查看函数的注释code
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)
运行结果:blog
holiday
这是一个放假通知
在被装饰的函数执行以前作的事
全体放假3天
在被装饰的函数执行以后作的事
好开心
带参数的装饰器:假如你有成千上万个函数使用了一个装饰器,如今你想把这些装饰器都取消掉,你要怎么作?一个一个的取消掉?utf-8
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.10001111030578613string
多个装饰器装饰同一个函数:io
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
是源函数的定义和注释