def fn(): print("原有功能") # 装饰器 def outer(tag): def inner(): tag() print(新增功能") return inner fn = outer(fn) fn()
开放封闭原则的实现
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def vase(): print('插花') #原功能:花瓶的作用 vase() def vase(): print('插花') print('绘画:进行观赏') # 1)增加观赏功能:不满足开放封闭原则,修改了源代码 vase() def wrap(fn): vase() print('绘画:进行观赏') # 2)增加观赏功能:不满足开放封闭原则,修改了调用方式 wrap(vase) def fn(): vase() print('绘画:进行观赏') # 3)满足了开放封闭原则,但是出现了函数调用的死循环 vase = fn vase() # 4)下方的函数嵌套结构就是装饰器 def wrap(tag): def fn(): tag() # 原有的vase print('绘画:进行观赏') return fn # 拓展功能后的vase vase = wrap(vase) # 将拓展功能后的功能函数重新赋值给vase vase() # 功能拓展了,且调用方式不变 ----------------------------------------------------------------------- # 了解:满足开放封闭原则,且可以达到装饰器的作用:拓展功能 def vase(): print('插花') tag = vase # 暴露在全局:很容易被修改掉 def fn(): tag() print('绘画:进行观赏') vase = fn vase() def wrap(tag): def fn(): tag() print('绘画:进行观赏') return fn vase = wrap(vase) vase() --------------------------------------------------------------------- # 1.0版本 def fn(): print('fn run') fn() # 2.0版本 def fn(): print('fn run0') print('fn run1') print('fn run2') fn() # 修改了源代码,没有更改调用方式,对外调用方式还是原来的,但功能要有所增加(开放) def fn(): print('fn run0') print('fn run') print('fn run2') fn() # 更改了调用方式,没有修改原功能代码(封闭) def wrap(fn): print('fn run0') fn() print('fn run2') wrap(fn)
def outer(f): def inner(): f() print("新增功能1") return inner def wrap(f): def inner(): f() print("新增功能2") return inner @wrap # 被装饰的顺序决定了新增功能的执行顺序 @outer # <==> fn = outer(fn): inner def fn(): print("原有功能")
示例:花瓶新增功能
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def outer(fn): def inner(): fn() print("绘画:进行观赏") return inner def wrap(fn): def inner(): fn() print('摆放功能') return inner # 语法糖 | 笑笑语法 @wrap @outer # <==> vase = outer(vase) def vase(): print('插花') # vase = outer(vase) vase()
叠加多个装饰器
import time def timmer(func): #func=wrapper2 def wrapper1(*args,**kwargs): start=time.time() res=func(*args,**kwargs) #res=wrapper2(*args,**kwargs) stop=time.time() print('run time is %s' %(stop - start)) return res return wrapper1 def auth(func): #func=最原始的那个index的内存地址 def wrapper2(*args,**kwargs): inp_user = input('please input your username: ').strip() inp_pwd = input('please input your password: ').strip() if inp_user == 'egon' and inp_pwd == '123': print('login successfull') res=func(*args,**kwargs) # 调用最原始的那个/也就是被装饰的那个函数 return res else: print('username or password error') return wrapper2 # 解释@语法的时候是自下而上运行 # 而执行装饰器内的那个wrapper函数时的是自上而下 @timmer # index=timmer(wrapper2) #index=wrapper1 @auth # index=auth(最原始的那个index的内存地址) #index=wrapper2 def index(): print('welcome to index page') time.sleep(3) index() #wrapper1()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#--------------------------------1------------------------------------ import time def timmer(func): print('timmer') def wrapper1(*args,**kwargs): start=time.time() res=func(*args,**kwargs) #res=wrapper2(*args,**kwargs) stop=time.time() print('run time is %s' %(stop - start)) return res return wrapper1 def auth(func): print('auth') def wrapper2(*args,**kwargs): inp_user = input('please input your username: ').strip() inp_pwd = input('please input your password: ').strip() if inp_user == 'egon' and inp_pwd == '123': print('login successfull') res=func(*args,**kwargs) # 调用最原始的那个/也就是被装饰的那个函数 return res else: print('username or password error') return wrapper2 @auth # index=auth(wrapper1) #index=wrapper2 @timmer #timmer(最原始的index)返回wrapper1 def index(): print('welcome to index page') time.sleep(3) index() #wrapper2() #------------------------------------2-------------------------------------------- import time def outter1(func1): #func1=wrapper2 print('outter1') def wrapper1(*args,**kwargs): print('wrapper1') res1=func1(*args,**kwargs) #res1=wrapper2(*args,**kwargs) return res1 return wrapper1 def outter2(func2): #func2=最原始的那个index的内存地址 print('outter2') def wrapper2(*args,**kwargs): print('wrapper2') res2=func2(*args,**kwargs) return res2 return wrapper2 @outter1 # index=outter1(wrapper2) #index=wrapper1 @outter2 #outter2(最原始的那个index的内存地址) ===> wrapper2 def index(): print('welcome to index page') time.sleep(3) index() #wrapper1()
def outer(func): def inner(*args, **kwargs): print("新增功能1") result = func(*args, **kwargs) print("新增功能2") return result return inner @outer def func(*args, **kwargs): print("原有功能") return "原有结果"
有参装饰器
def wrap(arg): def outer(func): def inner(*args, **kwargs): print("新增功能1") result = func(*args, **kwargs) print("新增功能2") return result return inner @wrap("装饰器参数") def func(*args, **kwargs): print("原有功能") return "原有结果"
示例:
def check_usr(fn): # fn, login, inner:不同状态下的login,所以参数是统一的 def inner(usr, pwd): # 在原功能上添加新功能 if not (len(usr) >= 3 and usr.isalpha()): print('账号验证失败') return False # 原有功能 result = fn(usr, pwd) # 在原功能下添加新功能 # ... return result return inner @check_usr def login(usr, pwd): if usr == 'abc' and pwd =='123qwe': print('登录成功') return True print('登录失败') return False
总结:
1.login有参数,所以inner与fn都有相同参数
2.login有返回值,所以inner与fn都有返回值
inner(usr, pwd):
res = fn(usr, pwd) # 原login的返回值
return res
login = check_usr(login) = inner
res = login('abc', '123qwe') # inner的返回值
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import time current_user={'username':None} # 补充:所有的数据类型的值自带布尔值,可以直接当作条件去用,只需要记住布尔值为假的那一些值即可(0,空,None) def login(engine='file'): #engine='mysql' def auth(func): #func=最原始那个index的内存地址 def wrapper(*args,**kwargs): if current_user['username']: print('已经登录过了,无需再次登陆') res=func(*args,**kwargs) return res if engine == 'file': inp_user = input('please input your username: ').strip() inp_pwd = input('please input your password: ').strip() if inp_user == 'egon' and inp_pwd == '123': print('login successfull') current_user['username']=inp_user # 在登陆成功之后立刻记录登录状态 res=func(*args,**kwargs) # res=最原始那个index的内存地址(*args,**kwargs) return res else: print('username or password error') elif engine == 'mysql': print('基于mysql的认证机制') elif engine == 'ldap': print('基于ldap的认证机制') else: print('无法识别的认证源') return wrapper return auth @login('file') #@auth # index=auth(最原始那个index的内存地址) #index=wrapper def index(): print('welcome to index page') time.sleep(3) @login('file') def home(name): print('welcome %s to home page' %name) time.sleep(2) return 123 index() #wrapper() res=home('egon') print(res)
# 有参装饰器的模板 def outter1(x,y,z): def outter2(func): def wrapper(*args,**kwargs): res=func(*args,**kwargs) return res return wrapper return outter2 # 无参装饰器的模板 def outter(func): def wrapper(*args,**kwargs): res=func(*args,**kwargs) return res return wrapper
装饰器的最终写法
def wrap(fn): def inner(*args, **kwargs): print('前增功能') result = fn(*args, **kwargs) print('后增功能') return result return inner @wrap def fn1(): print('fn1的原有功能') @wrap def fn2(a, b): print('fn2的原有功能') @wrap def fn3(): print('fn3的原有功能') return True @wrap def fn4(a, *, x): print('fn4的原有功能') return True fn1() fn2(10, 20) fn3() fn4(10, x=20)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def outer(input_color): def wrap(fn): if input_color == 'red': info = '