day3-python之装饰器(四)

一、简单的装饰器

装饰器本质上就是一个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 '''
多个装饰器装饰一个函数

day3-python之装饰器(四)

 六、进阶需求

第一种情况:

# 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)
统计多少个函数被装饰了

 day3-python之装饰器(四)

七、总结

# 装饰器的进阶
# 给装饰器加上一个开关 - 从外部传了一个参数到装饰器内
# 多个装饰器装饰同一个函数 - 套娃
# 每个装饰器都完成一个独立的功能
# 功能与功能之间互相分离
# 同一个函数需要两个或以上额外的功能
 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

相关推荐