装饰器

 装饰器概念

1 什么是装饰器
器=>工具
装饰=>指的是为被装饰对象添加新功能

装饰器本身可以是任意可调用的对象=>函数
被装饰的对象也可以是任意可调用的对象=>函数

目标:写一个函数来为另外一个函数添加新功能
2 为何要用装饰器
开放封闭原则: 软件一旦上线就应该对修改封闭,对扩展开放
对修改封闭:
1. 不能修改功能的源代码
2. 也不能修改功能的调用方式

对扩展开发:
可以为原有的功能添加新的功能
装饰器就是要在不修改功能源代码以及调用方式的前提下为原功能添加额外新的功能
3 如何用装饰器

装饰器代码

#统计不同程序的运行时间
import time
def index():
    print('welcome to index page')
    time.sleep(3)
#统计谁的时间,传谁
def outter(func):
    # func=最原始那个index的内存地址
    def wrapper():
        start = time.time()
        func()  # 最原始那个index的内存地址()
        stop = time.time()
        print('run time is %s' % (stop - start))
    return wrapper
#下面一行的目的是偷梁换柱
index = outter(index)  # index=outter(最原始那个index的内地址) #index=wrapper函数的内地址
                       #为了不改变调用方式,将变量名定义为index
index()                #调用wraper(),index的地址已经变成wrapper的地址

 装饰器修正1:

   #需要得到被装饰函数的返回值
1
import time 2 3 def index(): 4 print('welcome to index page') 5 time.sleep(3) 6 return 123 7 8 =================================== 9 def outter(func): 10 # func=最原始那个index的内存地址 11 def wrapper(): 12 start=time.time() 13 res=func() # 最原始那个index的内存地址() 14 stop=time.time() 15 print('run time is %s' %(stop-start)) 16 return res  #res是index()的返回值 17 return wrapper 18 19 index=outter(index) #index=outter(最原始那个index的内地址) #index=wrapper函数的内地址 20 =================================== 21 22 res=index() #res=wraper()实际调用 23 print(res) #打原始index()的返回值

装饰器修正2:

 1 #当对多个方法进行装饰时,需要传入不同参数
 2 import time
 3 
 4 def index():
 5     print('welcome to index page')
 6     time.sleep(3)
 7     return 123
 8 
 9 def home(name):
10     print('welcome %s to home page' %name)
11     time.sleep(1)
12 
13 #==================================
14 def outter(func):
15     # func=最原始那个home的内地址
16     def wrapper(*args,**kwargs):#可以传入任意参数,此处只是作为参数的中转,然后给传给func()
17         start=time.time()
18         res=func(*args,**kwargs)
19         stop=time.time()
20         print('run time is %s' %(stop-start))
21         return res
22     return wrapper
23 
24 index=outter(index) #index=outter(最原始那个index的内地址) #index=wrapper函数的内地址
25 home=outter(home) #index=outter(最原始那个home的内地址) #home=wrapper函数的内地址
26 #===================================
27 
28 home('egon') #wrapper('egon')
29 index() #wrapper()

 装饰器的语法糖:

@装饰器的名字:要在被装饰对象正上方单独一行写上
@timmer----->相当于func=timmer(func)括号内func-->为最原始的那个要被修饰的函数的内存地址)
 1 from functools import wraps#引用外部工具包来自动显示被装饰函数的方法名以及函数注释
 2 
 3 import time
 4 def timmer(func): # func=最原始那个home的内地址
 5     @wraps(func)
 6     def wrapper(*args,**kwargs):
 7         start=time.time()
 8         res=func(*args,**kwargs)
 9         stop=time.time()
10         print('run time is %s' %(stop-start))
11         return res
12     return wrapper
13 
14 @timmer  #index=timmer(index) #index=timmer(最原始那个index内存地址) #index=wrapper函数的内存地址
15 def index():
16     """这是index功能"""
17     print('welcome to index page')
18     time.sleep(3)
19     return 123
20 
21 @timmer  #home=timmer(home) #home=timmer(最原始那个home内存地址) #home=wrapper函数的内存地址
22 def home(name): 
23   """这是home功能"""
24   print('welcome %s to home page' %name)
25   time.sleep(1)
26
27 print(help(index))  #打印函数注释
28 print(index.__name__) #打印函数名

 无参装饰器与有参装饰器(核心都是偷梁换柱为wrapper函数):

无参装饰器(双层闭包函数):

#无参装饰器的模板
def outter(func):
    def wrapper(*args,**kwargs):
        res=func(*args,**kwargs)
        return res
    return wrapper

无参装饰器:

 1 #登录状态验证,账户验证
 2 import time
 3 
 4 user_info={'current_user':None}#定义初始用户状态
 5 
 6 def auth(func):
 7     def wrapper(*args,**kwargs):
 8         if user_info['current_user'] is not None:#说明已经登录了
 9             res=func(*args,**kwargs)
10             return res
11         inp_user=input('username>>>: ').strip()
12         inp_pwd=input('password>>>: ').strip()
13         if inp_user == 'egon' and inp_pwd == '123':
14             # 记录登录状态
15             user_info['current_user']=inp_user
16 
17             print('login successful')
18             res=func(*args,**kwargs)
19             return res
20         else:
21             print('user or password error')
22     return wrapper
23 
24 @auth
25 def index():
26     """这是index功能"""
27     print('welcome to index page')
28     time.sleep(2)
29     return 123
30 
31 @auth
32 def home(name):
33     """这是home功能"""
34     print('welcome %s to home page' %name)
35     time.sleep(1)
36 
37 index()
38 home('egon')

 有参装饰器(三层闭包函数,第三层用来传值

#有参装饰器模板
def outter2(xxx,yyy):
    def outter(func):    #被装饰函数名,不能加参数
        def wrapper(*args,**kwargs):#只是作为参数中转,不可加参数
            res=func(*args,**kwargs)
            print(xxx)  #要引用外部参数,只能通过外部函数传
            print(yyy)
            return res
        return wrapper
    return outter

 有参装饰器:

 1 #判断数据来源,根据不同来源做不同操作
 2 import time
 3 
 4 user_info={'current_user':None}
 5 
 6 def auth2(engine='file'):
 7     def auth(func):
 8         def wrapper(*args,**kwargs):
 9             if user_info['current_user'] is not None:
10                 res=func(*args,**kwargs)
11                 return res
12             inp_user=input('username>>>: ').strip()
13             inp_pwd=input('password>>>: ').strip()
14 
15             if engine == 'file':
16                 print('基于文件的认证')
17                 if inp_user == 'egon' and inp_pwd == '123':
18                     # 记录登录状态
19                     user_info['current_user']=inp_user
20 
21                     print('login successful')
22                     res=func(*args,**kwargs)
23                     return res
24                 else:
25                     print('user or password error')
26             elif engine == 'mysql':
27                 print('基于mysql数据的认证')
28             elif engine == 'ldap':
29                 print('基于ldap的认证')
30             else:
31                 print('无法识别认证源')
32         return wrapper
33     return auth
34 
35 @auth2(engine='mysql') # @auth ===> index=auth(最原始那个index的内存地址)===》index=wrapper
36 def index():
37     """这是index功能"""
38     print('welcome to index page')
39     time.sleep(2)
40     return 123
41 
42 @auth2(engine='file')
43 def home(name):
44     """这是home功能"""
45     print('welcome %s to home page' %name)
46     time.sleep(1)
47 
48 index()     #wrapper()
49 home('egon')#wrapper('egon')

 装饰器叠加:

加载装饰器就是将原函数名偷梁换柱成了装饰器最内层那个wrapper函数
在加载完毕后,调用原函数其实就是在调用wrapper函数

当一个被装饰的对象同时叠加多个装饰器时
  装饰器的加载顺序是:自下而上
  装饰器内wrapper函数的执行顺序是:自上而下

 1 import time
 2 
 3 def timmer(func): #func=wrapper2的内存地址
 4     def wrapper1(*args, **kwargs):
 5         print('==================>wrapper1运行了')
 6         start=time.time()
 7         res = func(*args, **kwargs) #===================>跳到wrapper2去执行了,
 8         stop=time.time()
 9         print('run time is %s' %(stop - start))
10         return res
11     return wrapper1
12 
13 def auth(engine='file'):
14     def xxx(func): # func=最原始那个index的内存地址
15         def wrapper2(*args, **kwargs):
16             print('================>wrapper2运行了')
17             name=input('username>>>: ').strip()
18             pwd=input('password>>>: ').strip()
19             if engine == 'file':
20                 print('基于文件的认证')
21                 if name == 'egon' and pwd  == '123':
22                     print('login successfull')
23                     res = func(*args, **kwargs)
24                     return res
25             elif engine == 'mysql':
26                 print('基于mysql的认证')
27             elif engine == 'ldap':
28                 print('基于ldap的认证')
29             else:
30                 print('错误的认证源')
31         return wrapper2
32     return xxx
33 
34 @timmer # index=timmer(wrapper2的内存地址) #index=wrapper1的内存地址
35 @auth(engine='file') #@xxx #index=xxx(最原始那个index的内存地址) #index=wrapper2的内存地址
36 def index():
37     print('welcome to index page')
38     time.sleep(2)
39 
40 index() #wrapper1的内存地址()
# ==================================>wrapper1运行了
# ===================================>wrapper2运行了
# username>>>: egon
# password>>>: 123
# 基于文件的认证
# login successfull
# welcome to index page
# run time is 11.126000165939331
 
 1 import time
 2 
 3 def timmer(func): #func=wrapper2的内存地址
 4     def wrapper1(*args, **kwargs):
 5         print('=================>wrapper1运行了')
 6         start=time.time()
 7         res = func(*args, **kwargs) #=================>跳到wrapper2去执行了,
 8         stop=time.time()
 9         print('run time is %s' %(stop - start))
10         return res
11     return wrapper1
12 
13 def auth(engine='file'):
14     def xxx(func): # func=最原始那个index的内存地址
15         def wrapper2(*args, **kwargs):
16             print('===============>wrapper2运行了')
17             name=input('username>>>: ').strip()
18             pwd=input('password>>>: ').strip()
19             if engine == 'file':
20                 print('基于文件的认证')
21                 if name == 'egon' and pwd  == '123':
22                     print('login successfull')
23                     res = func(*args, **kwargs)
24                     return res
25             elif engine == 'mysql':
26                 print('基于mysql的认证')
27             elif engine == 'ldap':
28                 print('基于ldap的认证')
29             else:
30                 print('错误的认证源')
31         return wrapper2
32     return xxx
33 
34 @auth(engine='file')
35 @timmer
36 def index():
37     print('welcome to index page')
38     time.sleep(2)
39 
40 index() #wrapper1的内存地址()
41
#===================================>wrapper2运行了
# username>>>: egon
# password>>>: 123
# 基于文件的认证
# login successfull
# ===================================>wrapper1运行了
# welcome to index page
# run time is 2.0189998149871826

原文地址:https://www.cnblogs.com/xuechengeng/p/9711861.html