一、简单的装饰器
装饰器本质上就是一个python函数,可以让其他函数在不需要任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。
简单来讲,在原有的函数前后增加功能,且不改变原函数的调用方式。
装饰器的本质:就是一个闭包函数
装饰器的应用场景:插入日志、性能测试、事务处理、缓存等等场景。
实现计算每个函数的执行时间的功能:
1 import time 2 def timmer(f): 3 def inner(): 4 start_time = time.time() 5 f() 6 end_time = time.time() 7 print(end_time - start_time) 8 return inner 9 10 def func(): 11 print('begin func') 12 time.sleep(0.1) 13 print('end func') 14 15 func = timmer(func) 16 func() # ==> inner()
以上功能不简洁,不完美。引出语法糖。
1 import time 2 def timmer(f): 3 def inner(): 4 start_time = time.time() 5 f() 6 end_time = time.time() 7 print(end_time - start_time) 8 return inner 9 10 @timmer # ==> func = timmer(func) 11 def func(): 12 print('begin func') 13 time.sleep(0.1) 14 print('end func') 15 16 func() # ==> inner()
以上装饰器都是不带参数函数,现在装饰一个带参数的该怎么办?
1 import time 2 def timmer(f): 3 def inner(*args,**kwargs): 4 start_time = time.time() 5 ret = f(*args,**kwargs) 6 end_time = time.time() 7 print(end_time - start_time) 8 return ret 9 return inner 10 11 @timmer # ==> func = timmer(func) 12 def func(a,b): 13 print('begin func',a) 14 time.sleep(0.1) 15 print('end func',b) 16 return True 17 18 func(1,2) # ==> inner()
1 import time
2
3 def timer(func):
4 def inner(a):
5 start = time.time()
6 func(a)
7 print(time.time() - start)
8 return inner
9
10 @timer
11 def func1(a):
12 print(a)
13
14 func1(1)
1 import time
2 def timer(func):
3 def inner(*args,**kwargs):
4 start = time.time()
5 re = func(*args,**kwargs)
6 end=time.time()
7 print(end- start)
8 return re
9 return inner
10
11 @timer #==> func1 = timer(func1)
12 def func1(a,b):
13 print('in func1')
14 print(a,b)
15
16 @timer #==> func1 = timer(func1)
17 def func2(a):
18 print('in func2 and get a:%s'%(a))
19 return 'fun2 over'
20
21 func1(1,2)
22 print(func2('aaaaaa'))
1 import time
2 def timer(func):
3 def inner(*args,**kwargs):
4 start = time.time()
5 re = func(*args,**kwargs)
6 end=time.time()
7 print(end - start)
8 return re
9 return inner
10
11 @timer #==> func1 = timer(func1)
12 def jjj(a):
13 print('in jjj and get a:%s'%(a))
14 return 'fun2 over'
15
16 jjj('aaaaaa')
17 print(jjj('aaaaaa'))
二、开放封闭原则
1.对扩展是开放的
任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。
2.对修改是封闭的
因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。
装饰器完美的遵循了这个开放封闭原则。
三、装饰器的固定结构
1 def timmer(f): 2 def inner(*args,**kwargs): 3 '''执行函数之前要做的''' 4 ret = f(*args,**kwargs) 5 '''执行函数之后要做的''' 6 return ret 7 return inner
装饰器的固定格式--wraps版
四、带参数的装饰器
带参数的装饰器:就是给装饰器传参
用处:就是当加了很多装饰器的时候,现在忽然又不想加装饰器了,想把装饰器给去掉,但是那么多代码,一个一个去显得麻烦,所以,可以利用带参数的装饰器去装饰它,就像一个开关,需要的时候就打开调用,不需要的时候就关闭去掉。给装饰器里面传个参数,那么这个语法糖也要带个括号。在语法糖括号内传参。可以用三层嵌套,弄一个标识
1 # 带参数的装饰器:(相当于开关)为了给装饰器传参
2 F=True#为True时就把装饰器给加上了
3 # F=False#为False时就把装饰器给去掉了
4 def outer(flag):
5 def wrapper(func):
6 def inner(*args,**kwargs):
7 if flag:
8 print('before')
9 ret=func(*args,**kwargs)
10 print('after')
11 else:
12 ret = func(*args, **kwargs)
13 return ret
14 return inner
15 return wrapper
16
17 @outer(F)#@wrapper
18 def hahaha():
19 print('hahaha')
20
21 @outer(F)
22 def shuangwaiwai():
23 print('shuangwaiwai')
24
25 hahaha()
26 shuangwaiwai()
五、多个装饰器装饰一个函数
1 def qqqxing(fun):
2 def inner(*args,**kwargs):
3 print('in qqxing: before')
4 ret = fun(*args,**kwargs)
5 print('in qqxing: after')
6 return ret
7 return inner
8
9 def pipixia(fun):
10 def inner(*args,**kwargs):
11 print('in qqxing: before')
12 ret = fun(*args,**kwargs)
13 print('in qqxing: after')
14 return ret
15 return inner
16 @qqqxing
17 @pipixia
18 def dapangxie():
19 print('饿了吗')
20 dapangxie()
21
22 '''
23 @qqqxing和@pipixia的执行顺序:先执行qqqxing里面的 print('in qqxing: before'),然后跳到了pipixia里面的
24 print('in qqxing: before')
25 ret = fun(*args,**kwargs)
26 print('in qqxing: after'),完了又回到了qqqxing里面的 print('in qqxing: after')。所以就如下面的运行结果截图一样
27 '''
六、进阶需求
第一种情况:
# 500个函数
# 设计你的装饰器 从而确认是够生效
1 import time 2 def outer(flag): 3 def timmer(f): 4 def inner(*args,**kwargs): 5 if flag == True: 6 start_time = time.time() 7 ret = f(*args,**kwargs) 8 end_time = time.time() 9 print(end_time - start_time) 10 else: 11 ret = f(*args,**kwargs) 12 return ret 13 return inner 14 return timmer 15 16 @outer(False) 17 def func(a,b): 18 print('begin func',a) 19 time.sleep(0.1) 20 print('end func',b) 21 return True 22 23 func(1,2)
第二种情况:
# 装饰器:登录、记录日志
1 login_info = {'alex':False} 2 def login(func): 3 def inner(name): 4 if login_info[name] != True: 5 user = input('user:') 6 pwd = input('pwd:') 7 if user == 'alex' and pwd == 'alex3714': 8 login_info[name] = True 9 if login_info[name] == True: 10 ret = func(name) 11 return ret 12 return inner 13 14 @login 15 def index(name): 16 print('欢迎%s来到博客园首页~' %name) 17 18 @login 19 def manager(name): 20 print('欢迎%s来到博客园管理页~' %name) 21 22 index('alex') 23 index('alex') 24 manager('alex') 25 manager('alex')
1 import time 2 login_info = {'alex':False} 3 def login(func): # manager 4 def inner(name): 5 if login_info[name] != True: 6 user = input('user :') 7 pwd = input('pwd :') 8 if user == 'alex' and pwd == 'alex3714': 9 login_info[name] = True 10 if login_info[name] == True: 11 ret = func(name) # timmer中的inner 12 return ret 13 return inner 14 15 def timmer(f): 16 def inner(*args,**kwargs): 17 start_time = time.time() 18 ret = f(*args,**kwargs) # 调用被装饰的方法 19 end_time = time.time() # 20 print(end_time - start_time) 21 return ret 22 return inner 23 24 @login 25 @timmer 26 def index(name): 27 print('欢迎%s来到博客园首页~'%name) 28 29 @login 30 @timmer # manager = login(manager) 31 def manager(name): 32 print('欢迎%s来到博客园管理页~'%name) 33 34 index('alex') 35 index('alex') 36 manager('alex') 37 manager('alex')
1 l=[]
2 def wrapper(fun):
3 l.append(fun)#统计当前程序中有多少个函数被装饰了
4 def inner(*args,**kwargs):
5 # l.append(fun)#统计本次程序执行有多少个带装饰器的函数被调用了
6 ret = fun(*args,**kwargs)
7 return ret
8 return inner
9
10 @wrapper
11 def f1():
12 print('in f1')
13
14 @wrapper
15 def f2():
16 print('in f2')
17
18 @wrapper
19 def f3():
20 print('in f3')
21 print(l)
七、总结
# 装饰器的进阶
# 给装饰器加上一个开关 - 从外部传了一个参数到装饰器内
# 多个装饰器装饰同一个函数 - 套娃
# 每个装饰器都完成一个独立的功能
# 功能与功能之间互相分离
# 同一个函数需要两个或以上额外的功能
1 def wrapper1(func): 2 def inner(*args,**kwargs): 3 '''执行a代码''' 4 ret = func(*args,**kwargs) 5 '''执行b代码''' 6 return ret 7 return inner 8 9 def wrapper2(func): 10 def inner(*args,**kwargs): 11 '''执行c代码''' 12 ret = func(*args,**kwargs) 13 '''执行d代码''' 14 return ret 15 return inner 16 17 @wrapper1 18 @wrapper2 19 def func():pass