目录python
器是指工具,而程序中的函数就是具有某一功能的工具,因此装饰器指的是为装饰器对象额外对象添加额外功能,所以定义装饰器就是定义一个函数,只不过该函数的功能是用来为其余函数添加额外功能的。mysql
须要注意的是:sql
若是咱们已经上线 了一个项目,须要修改某一个方法,可是咱们不想修改方法的使用方法,这个时候可使用装饰器。由于软件的维护应该遵循开发封闭原则,即软件于丹上线运行后,软件的维护对修改原码是封闭的,对扩展功能指的是开发的。mongodb
装饰器的实现必须遵照俩大规则:闭包
装饰器其实就是在遵照以上俩个原则的前提下被装饰对象添加新功能。app
改变源代码函数
import time def index(): start = time.time() print('welcome to index') time.sleep(1) end = time.time() print('运行时间:', end - start) index() #输出: welcome to index 运行时间: 1.0003464221954346
编写重复代码工具
import time def index(): print('welcome to index') time.sleep(1) def f2(): print('welcome to f2') time.sleep(1) start = time.time() index() end = time.time() print('运行时间:', end - start) start = time.time() f2() end = time.time() print('运行时间:', end - start) #输出: welcome to index 运行时间: 1.0001671314239502 welcome to f2 运行时间: 1.0003397464752197
第一种传参方式:改变调用方式code
import time def index(): print('welcome to index') time.sleep(1) def time_count(func): start = time.time() func() end = time.time() print('运行时间:', end - start) time_count(index) #输出: welcome to index 运行时间: 1.0005521774291992
第二种传参方式:包给函数-外包对象
import time def index(): print('welcome to index') time.sleep(1) def time_count(func): def wrapper(): start = time.time() func() end = time.time() print('运行时间:', end - start) return wrapper index = time_count(index) index() #输出: welcome to index 运行时间: 1.0000648498535156
上述的装饰器,最后调用index()的时候,实际上是在调用wrapper(),所以若是原始的index()有返回值的时候,wrapper()函数的返回值应该和index()的返回值相同,也就是说,咱们须要同步原始的index()和wrapper()方法的返回值。
import time def index(): print('welcome to index') time.sleep(1) return 123 def time_count(func): def wrapper(): start = time.time() res = func() end = time.time() print('运行时间:', end - start) return res return wrapper index = time_count(index) res = index() print(res) #输出: welcome to index 运行时间: 1.0007765293121338 123
若是原始的index()方法须要传参,那么咱们以前的装饰器是没法实现该功能的,因为有wrapper()=index(),因此给wrapper()方法传参便可。
import time def home(name): print(f'welcome {name} to home page') time.sleep(1) return name def time_count(func): def wrapper(*args, **kwargs): start = time.time() res = func(*args, **kwargs) end = time.time() print(f'{func} time is {end - start}') return res return wrapper home = time_count(home) res = home('chen') print('res:', res) #输出: welcome chen to home page <function home at 0x000002085D50B0D8> time is 1.0006473064422607 res: chen
在被装饰函数正上方,而且是单独一行写上@装饰器名
import time def time_count(func): def wrapper(*args, **kwargs): start = time.time() res = func(*args, **kwargs) end = time.time() print(f'{func} time is {end - start}') return res return wrapper @time_count def home(name): print(f'welcome {name} to home page') time.sleep(1) return name @time_count def index(): print('welcome to index') time.sleep(1) return 123 res = home('egon') print(f"res:{res}") #输出: welcome egon to home page <function home at 0x00000203FABAC948> time is 1.0005333423614502 res:egon
def func(): def wrapper(*args,**kwargs): res = func(*args,**kwargs) return res return wrapper
无参装饰器只套了两层,有参装饰器是套三层。
#登录注册的装饰器 import time current_user = {'username': None} def login(func): def wrapper(*args, **kwargs): if current_user['username']: res = func(*args, **kwargs) return res user = input('username:').strip() pwd = input('password:').strip() if user == 'chen' and pwd == '123': print('login successful') current_user['username'] = user res = func(*args, **kwargs) return res else: print('user or password error') return wrapper @login def home(name): print(f'welcome {name} to home page') time.sleep(1) return name @login def index(): print('welcome to index') time.sleep(1) return 123 res = index() #输出: username:chen password:123 login successful welcome to index
对于上面的登录注册,咱们把用户登录成功的信息写入内存文档中,可是在工业在,内存信息能够存在文本中,mysql中,mongodb中,可是咱们只能让用户信息来自于file
的用户能够认证,所以咱们能够改写上述的装饰器。
import time current_user = {'username': None} def login(func): def wrapper(*args, **kwargs): if current_user['username']: res = func(*args, **kwargs) return res user = input('username:').strip() pwd = input('password:').strip() engine = 'file' if engine == 'file': print('base of file') if user == 'chen' and pwd == '123': print('login successful') current_user['username'] = user res = func(*args, **kwargs) return res else: print('user or password error') elif engine == 'mysql': print('base of mysql') elif engine == 'mongodb': print('base of mongodb') else: print('default') return wrapper @login def home(name): print(f'welcome {name} to home page') time.sleep(1) @login def index(): print('welcome to index') time.sleep(1) res = index() #输出: username:chen password:123 base of file login successful welcome to index
三层简单实例
def f1(y): def f2(): x = 1 def f3(): print('x:', x) print('y:', y) return f3 return f2 f2 = f1(2) f3 = f2() f3() #输出: x: 1 y: 2
如今须要修改原来需求,须要判断用户动态的获取用户密码的方式,若是是file
类型的咱们则让用户进行认证,所以咱们须要使用,有参装饰器。
import time current_user = {'username': None} def auth(engine='file'): def login(func): def wrapper(*args, **kwargs): if current_user['username']: res = func(*args, **kwargs) return res user = input('username:').strip() pwd = input('password:').strip() if engine == 'file': print('base of file') if user == 'chen' and pwd == '123': print('登录成功') current_user['username'] = user res = func(*args, **kwargs) return res else: print('用户密码或者用户名错误') elif engine == 'mysql': print('base of mysql') elif engine == 'mongodb': print('base of mongodb') else: print('please base of file') return wrapper return login @auth(engine='mysql') def home(name): print(f'welcome {name} to home page') time.sleep(1) @auth(engine='file') def index(): print('welcome to index') time.sleep(1) res = index() #输出: username:chen password:123 base of file 登录成功 welcome to index
因为倆层的装饰器,参数必须得固定定位func
,可是三层的装饰器解除了这个限制,咱们不单单可使用上述单个参数的三层装饰器,多个参数的只须要在三层装饰器中多家几个参数便可,也就是说装饰器三层便可,多加无用。
def outter1(func): # func = wrapper2 def wrapper1(*args, **kwargs): # wrapper是将来要运行的函数 print('------------') res = func(*args, **kwargs) # func是被装饰的函数 # wrapper2 print('------------') return res return wrapper1 def outter2(func): # func = index def wrapper2(*args, **kwargs): # wrapper是将来要运行的函数 print('11111111111111') res = func(*args, **kwargs) # func是被装饰的函数 # index() print('11111111111111') return res return wrapper2 # @outter1 # index = outter1(index) # @outter2 # index = outter2(index) # 先运行最下面的装饰器 # # index def index(): print('index') # index从新定义的index = outter2(index 真正的index) index = outter2(index) # index = wrapper2 # index再一次从新定义的index = outter1(index从新定义的index,即wrapper2) index = outter1(index) # index = wrapper1 index() # wrapper1() #输出: ------------ 11111111111111 index 11111111111111 ------------
def outter(func): def wrapper(*args,**kwargs): #加功能 res = func(*args,**kwargs) return res return wrapper
主要是用来给 倆层装饰器添加参数
def sanceng(engine): def outter(func): def wrapper(*args, **kwargs): # 加功能 print(engine) res = func(*args, **kwargs) return res return wrapper return outter @sanceng('file') def shopping(): print('shopping') shopping() #输出:file shopping