一.今日內容總覽python
關於函數的裝飾器
1.裝飾器(重點,難點)(要求:反覆寫,代碼很少可是很繞)
開閉原則:(好比,菜單是拆散的,一點點搞的,用友拆散本身的功能,之後就不用開發了)
(1)對功能的擴展開放
(2)對代碼的修改是封閉的
通用裝飾器語法:
def wrapper(fn):
def inner(*args,**kwargs): #聚合
#在目標函數以前的操做
ret=fn(*args,**kwargs) #打散
在目標函數以後
return inner
@wrapper #等價於 func=wrapper(func)
def func():
pass
func()
NC(用友,腦殘)
2.同一個函數 被多個裝飾器裝飾
@wrapper1
@wrapper2
@wrapper3
def func():
pass
1 2 3 func 3 2 1
總結:就近原則,一層一層寫
3.帶參數的裝飾器(難受)(明白函數的調用就行)
def wrapper_out(參數):
def wrapper(fn):
def inner(*args,**kwargs): #聚合
#在目標函數以前
ret=fn(*args,**kwargs) #打散
#在目標函數以後
return ret
return inner
return wrapper
@wrapper_out(實參) #執行的時候,先執行函數調用,而後使用返回值和前面的@組合成裝飾器語法糖
def func():
pass
二.今日內容大綱app
1.開閉原則函數
2.裝飾器測試
3.帶參數的裝飾器優化
4.多個裝飾器裝飾同一個函數spa
5.裝飾器的應用設計
三.今日內容詳解代理
1.開閉原則日誌
開閉原則:
對功能的擴展開放;
對代碼的修改是封閉的.
def chi(): print('吃東西') print('喝東西') chi() chi() #顯然不是咱們想要的,對程序繼續優化
2.裝飾器code
(1)
女媧 造人 補天
熱插拔:有時須要,有時不須要,這纔是程序須要的
def zaoren(): # print('澆水') #此需求有的時候須要,有的時候不須要 print('捏個泥人') print('吹口仙氣') print('就出來人了') zaoren() zaoren() zaoren()
上面的寫法依然沒知足咱們的需求
(2)
#三年大旱,沒有水? def zaoren(): # print('澆水') #此需求有的時候須要,有的時候不須要 print('捏個泥人') print('吹口仙氣') print('就出來人了') def water(): print('澆水') zaoren() zaoren() #不能一直修改這兩行代碼 water() #這時的設計就不符合開閉原則
(3)裝飾器的源頭
# # 裝飾器 def wrapper(fn): # fn接收的是一個函數 def inner(): print("澆水") fn() # 調用你傳遞進來的函數 print("睡一覺") return inner def zaoren(): print("捏個泥人") print("吹口仙氣") print("你就出來了") zaoren = wrapper(zaoren) zaoren() zaoren()
(4)lol & 消消樂
#lol def lol(): print('雙擊lol') print('選擇狂戰士') print('進草叢') print('崩山擊,十字斬') #開心消消樂 def kxxxl(): print('雙擊消除') print('進入下一關') print('升級') print('繼續玩') #開掛 #關閉外掛 def wrapper(fn): def inner(): print('開掛') fn() print('關閉外掛') return inner #lol裝飾器 lol=wrapper(lol) lol() # #kxxxl裝飾器 kxxxl=wrapper(kxxxl) kxxxl() ''' 結果: 開掛 雙擊lol 選擇狂戰士 進草叢 崩山擊,十字斬 關閉外掛 開掛 雙擊消除 進入下一關 升級 繼續玩 關閉外掛 '''
(5)
裝飾器傳參
def play(username,password): print('雙擊lol') print('登陸',username,password) print('選擇狂戰士') print('進草叢') print('崩山擊,十字斬') return '十字斬刀者' def xiaoxiaole(qq): print('登陸qq帳號') print('消消樂')
開掛
關閉外掛
在目標函數前和後插入一段新的代碼,不改變原來的代碼
方法一:(投機版)
def wrapper(fn): #fn=play def inner(*args,**kwargs):#無敵傳參 聚合接收到的是元組('alex',123) print('開掛') fn(*args,**kwargs) print('關閉外掛') return '十字斬刀者' return inner play=wrapper(play) #play=inner 左邊的play表明inner w=play('alex','123') print(w) #在這裏返回的是inner的return xiaoxiaole=wrapper(xiaoxiaole) xiaoxiaole(11010)
方法二:
def wrapper(fn): #fn=play def inner(*args,**kwargs):#無敵傳參 聚合接收到的是元組('alex',123) print('開掛') s=fn(*args,**kwargs) #這裏也有變化 print('關閉外掛') return s #這裏返回的接收的是內部函數的,若是play沒有返回值,返回None return inner play=wrapper(play) #play=inner 左邊的play表明inner w=play('alex','123') print(w) #在這裏返回的是play的return
(6)
通用裝飾器寫法:(寫10遍以上!!!)
#python裏面的動態代理 #存在的意義:在不破壞原有函數和原有函數調用的基礎上,給函數添加新的功能 #inner至關於代理 def wrapper(fn): #fn是目標函數 def inner(*args,**kwargs): #爲了目標函數的傳參 '''在執行目標函數以前''' ret=fn(*args,**kwargs) #調用目標函數,ret是目標函數的返回值 '''在執行目標函數以後的操做,能夠加if判斷等等''' return ret #目標函數返回值返回,保證函數正常的結束 return inner @wrapper #target_func=wrapper(target_func) def target_func(): pass #target_func=wrapper(target_func) #此時上面的fn就是target_func target_func() #此時執行的是inner # #注意:不要用打印當成返回值
3.帶參數的裝飾器
def wrapper_out(flag): #裝飾器自己的參數 def wrapper(fn): #目標函數 def inner(*args,**kwargs): #目標函數執行須要的參數 if flag==True: print('問問金老闆,最近行情怎麼樣啊?') ret=fn(*args,**kwargs) #在執行目標函數以前 print('金老闆再騙我,恨你') return ret else: ret=fn(*args,**kwargs) #在執行目標函數以前 return ret return inner return wrapper @wrapper_out(True) #先執行wrapper_out(True) 返回一個裝飾器wrapper 再和@拼接 @裝飾器 # wrapper_out(True) # yue=wrapper(yue) #左邊的yue返回值是inner,右邊的yue纔是真正的下面的yue def yue(): #被wrapper裝飾 print('走啊,約不?') yue() #執行yue,這裏的yue是指inner,
結果測試:
''' False: 走啊,約不? True: 問問金老闆,最近行情怎麼樣啊? 走啊,約不? 金老闆再騙我,恨你 '''
4.多個裝飾器裝飾同一個函數
def wrapper1(fn): def inner(*args, **kwargs): print("1111111") ret = fn(*args, **kwargs) print("2222222") return ret return inner def wrapper2(fn): def inner(*args, **kwargs): print("3333333") ret = fn(*args, **kwargs) print("44444444") return ret return inner def wrapper3(fn): def inner(*args, **kwargs): print("555555") ret = fn(*args, **kwargs) print("666666") return ret return inner # 就近原則 @wrapper1 @wrapper2 @wrapper3 def func(): print("我是可憐的func") func() #本身總結:把最終要執行的核心語句當成魚的大刺對稱吃魚原則 # 1 2 3 func 3 2 1
5.裝飾器的應用
menu = ("查看", "添加", "修改", "刪除", "退出") flag = False # 沒登陸 def login(): global flag username = input("請輸入用戶名:") password = input("請輸入密碼:") if username == "alex" and password == "123": flag = True print("登陸") else: flag = False print("用戶名密碼錯誤") # 登陸驗證裝飾器函數 def login_verify(fn): def inner(*args, **kwargs): # 登陸校驗 while 1: if flag == True: ret = fn(*args, **kwargs) return ret else: print('對不起, 您尚未登陸') login() return inner def chakan(): print("==============================查看") @login_verify def tianjia(): print("============================添加") @login_verify def xiugai(): print("=======================修改") @login_verify def shanchu(): print("=========================刪除") while 1: for i in range(len(menu)): print(i+1, menu[i]) num = input("請輸入你要執行的菜單:") if num == "1": chakan() elif num == "2": tianjia() elif num == "3": xiugai() elif num == "4": shanchu() elif num == "5": print("程序退出中..........") exit() else: print("輸入有誤. 請從新選擇!")
做業:
1.整理裝飾器的造成過程, 背誦裝飾器的固定格式
#裝飾器通用寫法 #存在的意義:在不破壞原有函數和原有函數調用的基礎上,給函數添加新的功能 #inner至關於代理 def wrapper(fn): #fn是目標函數 def inner(*args,**kwargs): #爲了目標函數的傳參 '''在執行目標函數以前的操做''' ret=fn(*args,**kwargs) #調用目標函數,ret是目標函數的返回值 '''在執行目標函數以後的操做,能夠加if判斷等等''' return ret #目標函數返回值返回,保證函數正常的結束 return inner @wrapper #target_func=wrapper(target_func) def target_func(): # print('1') pass #target_func=wrapper(target_func) #此時上面的fn就是target_func target_func() #此時執行的是inner #注意:不要用打印當成返回值
2.編寫裝飾器, 在每次執行被裝飾函數以前打印」
每次執行被裝飾函數之前都要先通過這裏, 這裏根據需求添加代碼」
def wrapper(fn): #fn是目標函數 def inner(*args,**kwargs): #爲了目標函數的傳參 '''在執行目標函數以前的操做''' ret=fn(*args,**kwargs) #調用目標函數,ret是目標函數的返回值 return ret #目標函數返回值返回,保證函數正常的結束 return inner @wrapper #target_func=wrapper(target_func) def target_func(): pass #target_func=wrapper(target_func) #此時上面的fn就是target_func target_func() #此時執行的是inner
3.編寫裝飾器, 在每次執行被裝飾函數以前打印」
每次執行被裝飾函數之後都要通過這裏, 這裏根據需求添加代碼」
def wrapper(fn): #fn是目標函數 def inner(*args,**kwargs): #爲了目標函數的傳參 ret=fn(*args,**kwargs) #調用目標函數,ret是目標函數的返回值 '''在執行目標函數以後的操做,能夠加if判斷等等''' return ret #目標函數返回值返回,保證函數正常的結束 return inner @wrapper #target_func=wrapper(target_func) def target_func(): pass #target_func=wrapper(target_func) #此時上面的fn就是target_func target_func() #此時執行的是inner
4.編寫裝飾器, 在每次執行被裝飾函數以前讓用戶輸入用戶名,
密碼, 給用戶三次機會, 登陸成功以後, 才能訪問該函數
def login(): global flag count=1 #方法一: # while 1: # username = input("請輸入用戶名:") # password = input("請輸入密碼:") # #3次失敗,直接離開整個程序 # if username == "alex" and password == "123": # flag = True #重點:登錄成功以後,改變全局變量爲True # print("登陸成功") #登錄成功,直接進入下一步 # break # else: # flag = False # print("用戶名密碼錯誤") # if count==3: #if放在下邊和上邊是不同的 # exit() # count+=1 # else: # print('您已經輸入錯誤了3次') #方法二: # while count<4: # username = input("請輸入用戶名:") # password = input("請輸入密碼:") # #3次失敗,直接離開整個程序 # if username == "alex" and password == "123": # flag = True #重點:登錄成功以後,改變全局變量爲True # print("登陸成功") #登錄成功,直接進入下一步 # break # else: # flag = False # print("用戶名密碼錯誤") # # if count==3: #if放在下邊和上邊是不同的 # # exit() # count+=1 # print(count) # else: # print('您已經輸入錯誤了3次') # exit() #方法三: # for i in range(3): # username = input("請輸入用戶名:") # password = input("請輸入密碼:") # #3次失敗,直接離開整個程序 # if username == "alex" and password == "123": # flag = True #重點:登錄成功以後,改變全局變量爲True # print("登陸成功") #登錄成功,直接進入下一步 # break # else: # flag = False # print("用戶名密碼錯誤") # # if count==3: #if放在下邊和上邊是不同的 # # exit() # count+=1 # print(count) # else: # print('您已經輸入錯誤了3次') # exit() flag = False # 沒登陸 def wrapper(fn): #fn是目標函數 def inner(*args, **kwargs): # 登陸校驗 while 1: if flag == True: #問題:函數是怎麼走這塊的? ret = fn(*args, **kwargs) return ret else: print('你好,請您登錄!') login() return inner @wrapper #target_func=wrapper(target_func) def target_func(): print('冬瓜你好') #target_func=wrapper(target_func) #此時上面的fn就是target_func target_func() #此時執行的是inner
5.編寫裝飾器, 爲多個函數加上認證功能(用戶的帳戶密碼來源於文件,
用戶有三次登陸的機會), 要求, 若是用戶登陸成功了, 後續就不須要再次登陸了.
def login(): global flag count=1 #方法一: s=1 while s: username = input("請輸入用戶名:") password = input("請輸入密碼:") #3次失敗,直接離開整個程序 with open('info', mode='r', encoding='utf-8') as f: for i in f.readlines(): t_user,t_pwd=i.split('|') if username == t_user and password == t_pwd: flag = True #重點:登錄成功以後,改變全局變量爲True print("登陸成功") #登錄成功,直接進入下一步 # break s=0 else: flag = False print("用戶名密碼錯誤") count += 1 #注意應該在這裏,把每次錯誤的數字+1 if count == 4: # if放在下邊和上邊是不同的 print('您已經輸入錯誤了3次') exit() else: print('進入下一步') flag = False # 沒登陸 def wrapper(fn): #fn是目標函數 def inner(*args, **kwargs): # 登陸校驗 while 1: if flag == True: #問題:函數是怎麼走這塊的? ret = fn(*args, **kwargs) return ret else: print('你好,請您登錄!') login() return inner @wrapper #target_func=wrapper(target_func) def target_func(): print('冬瓜你好') #target_func=wrapper(target_func) #此時上面的fn就是target_func target_func() #此時執行的是inner
6.給每一個函數寫一個記錄日誌的功能. 功能要求: 每一次調用函數以前, 要將函數名稱, 事件節點記錄到log的日誌中. 所需模塊:import timeprint(time.strftime(「%Y-%m-%d %H:%M:%S」))