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