一、什么是装饰器
解释:
器即函数
装饰即修饰,意指为其他函数添加新功能
装饰器的定义:本质上就是函数,功能是为其他函数添加新的功能
二、装饰器需要遵循的原则
原则:
1、不修改被装饰函数的源代码(开放封闭原则)
2、为被装饰函数添加新功能后,不修改被修饰函数的调用方式
三、实现装饰器知识储备
装饰器=高阶函数+函数嵌套+闭包
四、高阶函数
高阶函数的定义:
1、函数接收的参数是一个函数名
2、函数的返回值是一个函数名
3、满足上述条件任意一个,都可称之为高阶函数
1 def foo(): 2 print('我的函数名作为参数传给高阶函数') 3 4 def gaojie1(func): 5 print('我就是高阶函数1,我接收的参数名为%s'%func) 6 func() 7 8 def gaojie2(func): 9 print('我就是高阶函数2,我的返回值是%s'%func) 10 return func 11 12 gaojie1(foo) 13 gaojie2(foo)
输出结果:
1 我就是高阶函数1,我接收的参数名为<function foo at 0x0000000002081EA0> 2 我的函数名作为参数传给高阶函数 3 我就是高阶函数2,我的返回值是<function foo at 0x0000000002081EA0>
应用一:把函数作为参数传递给高阶函数
1 # 高阶函数的应用1:把函数作为参数传给高阶函数 2 import time 3 def foo(): 4 print('from the foo') 5 6 def timmer(func): 7 start_time=time.time() 8 time.sleep(1) 9 func() 10 stop_time=time.time() 11 print('函数%s,运行时间是%s'%(func,stop_time-start_time)) 12 13 timmer(foo) 14 #总结:我们确实为函数foo增加了foo运行时间的功能,但是foo原来的 15 #执行方式是foo(),现在我们需要高阶函数timmer(foo),改变了函数的 16 #调用方式
应用二:把函数名当做参数传递给高阶函数,高阶函数直接返回函数名
1 #高阶函数应用2:把函数名当做参数传给高阶函数,高阶函数直接返回函数名 2 import time 3 def foo(): 4 print('from the foo') 5 6 def timmer(func): 7 start_time=time.time() 8 return func 9 stop_time=time.time() 10 print('函数%s运行时间是%s'%(func,stop_time-start_time)) 11 foo=timmer(foo) 12 foo() 13 #总结:我们确实没有改变foo的调用方式,但是我们也没有为foo增加任何功能
高阶函数总结:
1、函数接收的参数是一个函数名
作用:在不修改函数源代码的前提下,为函数添加新功能
不足:会改变函数的调用方式
2、函数的返回值是一个函数名
作用:不修改函数的调用方式
不足:不能添加新的功能
五、函数嵌套
描述:在函数内部定义函数
代码:
1 def father(name): 2 print('from father %s'%name) 3 def son(): 4 print('from son') 5 def grandson(): 6 print('from grandson') 7 grandson() 8 son() 9 10 father('baba')
六、闭包
1 # 闭包:在一个作用域里放入定义变量,相当于打了一个包 2 def father(name): 3 def son(): 4 #name='alex' 5 print('我爸爸是[%s]' %name) 6 def grandson(): 7 #name='alex' 8 print('我的爷爷是[%s]'%name) 9 grandson() 10 son() 11 father('alex')
七、无参装饰器
无参修饰器=高级函数+函数嵌套
基本框架:
1 #这就是一个实现一个装饰器最基本的架子 2 def timer(func): 3 def wrapper(): 4 func() 5 return wrapper
加上参数:
1 def timer(func): 2 def wrapper(*args,**kwargs): 3 func(*args,**kwargs) 4 return wrapper
加上功能:
1 import time 2 def timer(func): 3 def wrapper(*args,**kwargs): 4 start_time=time.time() 5 func(*args,**kwargs) 6 stop_time=time.time() 7 print('函数%s,运行时间是%s',%(func,stop_time-start_time)) 8 return wrapper
加上返回值:
1 import time 2 def timer(func): 3 def wrapper(*args,**kwargs): 4 start_time=time.time() 5 res=func(*args,**kwargs) 6 stop_time=time.time() 7 print('函数%s,运行时间%s'%(func,stop_time-start_time)) 8 return res 9 return wrapper
使用修饰器:
1 import time 2 def timer(func): 3 def wrapper(*args,**kwargs): 4 start_time=time.time() 5 res=func(*args,**kwargs) 6 stop_time=time.time() 7 print('函数%s,运行时间%s'%(func,stop_time-start_time)) 8 return res 9 return wrapper 10 11 def cal(array): 12 res=0 13 for i in array: 14 res+=i 15 return res 16 cal=timer(cal) 17 print(cal(range(10)))
语法糖@:
1 import time 2 def timer(func): 3 def wrapper(*args,**kwargs): 4 start_time=time.time() 5 res=func(*args,**kwargs) 6 stop_time=time.time() 7 print('函数%s,运行时间%s'%(func,stop_time-start_time)) 8 return res 9 return wrapper 10 @timer 11 def cal(array): 12 res=0 13 for i in array: 14 res+=i 15 return res 16 #cal=timer(cal) 17 print(cal(range(10)))
八、装饰器应用示例
1 user_list=[ 2 {'name':'alex','passwd':'123'}, 3 {'name':'wangjun','passwd':'123'}, 4 {'name':'liuchao','passwd':'123'}, 5 {'name':'qiaobusi','passwd':'123'} 6 ] 7 current_user={'username':None,'login':False} 8 9 def auth_deco(func): 10 def wrapper(*args,**kwargs): 11 if current_user['username'] and current_user['login']: 12 res=func(*args,**kwargs) 13 return res 14 username=input('用户名:').strip() 15 passwd=input('密码:').strip() 16 for index,user_dic in enumerate(user_list): 17 if username==user_dic['name'] and passwd==user_dic['passwd']: 18 current_user['username']=username 19 current_user['login']=True 20 res=func(*args,**kwargs) 21 return res 22 break 23 else: 24 print('用户名或者密码错误') 25 return wrapper 26 27 @auth_deco 28 def index(): 29 print('欢迎来到主页面') 30 31 @auth_deco 32 def home(): 33 print('这里是你家') 34 35 def shopping_car(): 36 print('查看购物车啊亲') 37 38 def order(): 39 print('查看订单啊亲') 40 41 index() 42 home()
1 user_list=[ 2 {'name':'alex','passwd':'123'}, 3 {'name':'linhaifeng','passwd':'123'}, 4 {'name':'wupeiqi','passwd':'123'}, 5 {'name':'yuanhao','passwd':'123'}, 6 ] 7 8 current_user={'username':None,'login':False} 9 def auth(auth_type='file'): 10 def auth_deco(func): 11 def wrapper(*args,**kwargs): 12 if auth_type == 'file': 13 if current_user['username'] and current_user['login']: 14 res=func(*args,**kwargs) 15 return res 16 username=input('用户名: ').strip() 17 passwd=input('密码: ').strip() 18 19 for index,user_dic in enumerate(user_list): 20 if username == user_dic['name'] and passwd == user_dic['passwd']: 21 current_user['username']=username 22 current_user['login']=True 23 res=func(*args,**kwargs) 24 return res 25 break 26 else: 27 print('用户名或者密码错误,重新登录') 28 elif auth_type == 'ldap': 29 print('巴拉巴拉小魔仙') 30 res=func(*args,**kwargs) 31 return res 32 return wrapper 33 return auth_deco 34 35 36 #auth(auth_type='file')就是在运行一个函数,然后返回auth_deco,所以@auth(auth_type='file') 37 #就相当于@auth_deco,只不过现在,我们的auth_deco作为一个闭包的应用,外层的包auth给它留了一个auth_type='file'参数 38 @auth(auth_type='ldap') 39 def index(): 40 print('欢迎来到主页面') 41 42 @auth(auth_type='ldap') 43 def home(): 44 print('这里是你家') 45 46 def shopping_car(): 47 print('查看购物车啊亲') 48 49 def order(): 50 print('查看订单啊亲') 51 52 # print(user_list) 53 index() 54 # print(user_list) 55 home() 56 57 带参装饰器
九、超时装饰器
1 import sys,threading,time 2 3 4 class KThread(threading.Thread): 5 6 """A subclass of threading.Thread, with a kill() 7 8 method. 9 10 11 12 Come from: 13 14 Kill a thread in Python: 15 16 http://mail.python.org/pipermail/python-list/2004-May/260937.html 17 18 """ 19 20 def __init__(self, *args, **kwargs): 21 22 threading.Thread.__init__(self, *args, **kwargs) 23 24 self.killed = False 25 26 27 28 def start(self): 29 30 """Start the thread.""" 31 32 self.__run_backup = self.run 33 34 self.run = self.__run # Force the Thread to install our trace. 35 36 threading.Thread.start(self) 37 38 39 40 def __run(self): 41 42 """Hacked run function, which installs the 43 44 trace.""" 45 46 sys.settrace(self.globaltrace) 47 48 self.__run_backup() 49 50 self.run = self.__run_backup 51 52 53 54 def globaltrace(self, frame, why, arg): 55 56 if why == 'call': 57 58 return self.localtrace 59 60 else: 61 62 return None 63 64 65 66 def localtrace(self, frame, why, arg): 67 68 if self.killed: 69 70 if why == 'line': 71 72 raise SystemExit() 73 74 return self.localtrace 75 76 77 78 def kill(self): 79 80 self.killed = True 81 82 83 84 class Timeout(Exception): 85 86 """function run timeout""" 87 88 89 90 def timeout(seconds): 91 92 """超时装饰器,指定超时时间 93 94 若被装饰的方法在指定的时间内未返回,则抛出Timeout异常""" 95 96 def timeout_decorator(func): 97 98 """真正的装饰器""" 99 100 101 102 def _new_func(oldfunc, result, oldfunc_args, oldfunc_kwargs): 103 104 result.append(oldfunc(*oldfunc_args, **oldfunc_kwargs)) 105 106 107 108 def _(*args, **kwargs): 109 110 result = [] 111 112 new_kwargs = { # create new args for _new_func, because we want to get the func return val to result list 113 114 'oldfunc': func, 115 116 'result': result, 117 118 'oldfunc_args': args, 119 120 'oldfunc_kwargs': kwargs 121 122 } 123 124 thd = KThread(target=_new_func, args=(), kwargs=new_kwargs) 125 126 thd.start() 127 128 thd.join(seconds) 129 130 alive = thd.isAlive() 131 132 thd.kill() # kill the child thread 133 134 if alive: 135 136 raise Timeout(u'function run too long, timeout %d seconds.' % seconds) 137 138 else: 139 140 return result[0] 141 142 _.__name__ = func.__name__ 143 144 _.__doc__ = func.__doc__ 145 146 return _ 147 148 return timeout_decorator 149 150 151 @timeout(5) 152 153 def method_timeout(seconds, text): 154 155 print('start', seconds, text) 156 157 time.sleep(seconds) 158 159 print('finish', seconds, text) 160 161 return seconds 162 163 164 method_timeout(6,'asdfasdfasdfas')