def fn(): print("原有功能") # 裝飾器 def outer(tag): def inner(): tag() print(新增功能") return inner fn = outer(fn) fn()
開放封閉原則的實現
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)
mysql
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("原有功能")
示例:花瓶新增功能
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()
疊加多個裝飾器web
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()
#--------------------------------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 "原有結果"
示例:sql
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的返回值
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)
def outer(input_color): def wrap(fn): if input_color == 'red': info = '\033[36;41mnew action\33[0m' else: info = 'yellow:new action' def inner(*args, **kwargs): pass result = fn(*args, **kwargs) print(info) return result return inner return wrap # outer(color) => wrap color = input('color: ') @outer(color) # @outer(color) ==> @wrap # func => inner def func(): print('func run') func()
登陸認證功能app
is_login = False # 登陸狀態 def login(): usr = input('usr: ') if not (len(usr) >= 3 and usr.isalpha()): print('帳號驗證失敗') return False pwd = input('pwd: ') if usr == 'abc' and pwd =='123qwe': print('登陸成功') is_login = True else: print('登陸失敗') is_login = False # 完成一個登陸狀態校驗的裝飾器 def check_login(fn): def inner(*args, **kwargs): # 查看我的主頁或銷售功能前:若是沒有登陸先登陸,反之能夠進入其功能 if is_login != True: print('你未登陸') login() # 查看我的主頁或銷售 result = fn(*args, **kwargs) return result return inner # 查看我的主頁功能 @check_login def home(): print('我的主頁') # 銷售功能 @check_login def sell(): print('能夠銷售') home()
from functools import wraps def outer(func): @wraps(func) def inner(*args, **kwargs): '''裝飾器文檔註釋''' func(*args, **kwargs) return inner @outer def func(*args, **kwargs): '''原有文檔註釋''' print("原有功能")