Python全棧(第一期)Day12
今日主要內容:
裝飾器的進階
1,functools.wraps
2,帶引數的裝飾器
3,多個裝飾器裝飾同一個函式
一,裝飾器複習
def wrapper(func): def inner(*args,**kwargs): print('在被裝飾的函式執行之前做的事') ret = func(*args, **kwargs) print('在被裝飾的函式執行之後做的事') return ret return inner @wrapper #holiday = wrapper(holiday) def holiday(day): print('全體放假%s天' % day) return '好開心' ret = holiday(3) print(ret)
輸出結果:
在被裝飾的函式執行之前做的事
全體放假3天
在被裝飾的函式執行之後做的事
好開心
知識補充:
#區分這幾種情況一起*的作用! #*args不是在哪兒都能用的 只是print這裡可以 因為print有一個引數:*args def outer(*args): print(args) print(*args) def inner(*args): print('inner : ', args) inner(*args) outer(1, 2, 3, 4) #==outer(*[1,2,3,4]) #==outer(*(1,2,3,4)) # 接收的時候聚合 呼叫的時候打散
輸出結果;
(1, 2, 3, 4)
1 2 3 4
inner : (1, 2, 3, 4)
二,實戰
1,編寫裝飾器,求登入成功一次,後續的函式都無需再輸入使用者名稱和密碼。
FLAG = False def login(func): def inner(*args, **kwargs): global FLAG '''登入程式''' if FLAG: ret = func(*args, **kwargs) # func是被裝飾的函式 return ret else: username = input('username : ') password = input('password : ') if username == 'nanshan' and password == '520': FLAG = True ret = func(*args, **kwargs) #func是被裝飾的函式 return ret else: print('登入失敗') return inner @login def shoplist_add(): print('增加一件物品') @login def shoplist_del(): print('刪除一件物品') shoplist_add() shoplist_del()
輸出結果:
username : nanshan
password : 520
增加一件物品
刪除一件物品
很明顯:shoplist_del() 並沒有要求重新輸入使用者名稱。
2,編寫裝飾器,為多個函式加上記錄呼叫功能,要求每次呼叫函式都將被呼叫的函式名稱寫入檔案。
def log(func):
def inner(*args, **kwargs):
with open('log', 'a', encoding='utf-8') as f:
f.write(func.__name__+'\n')
ret = func(*args, **kwargs)
return ret
return inner
@log
def shoplist_add():
print('增加一件物品')
@log
def shoplist_del():
print('刪除一件物品')
shoplist_add()
shoplist_del()
shoplist_del()
shoplist_del()
shoplist_del()
shoplist_del()
輸出結果:
增加一件物品
刪除一件物品
刪除一件物品
刪除一件物品
刪除一件物品
刪除一件物品
開啟log檔案:
shoplist_add
shoplist_del
shoplist_del
shoplist_del
shoplist_del
shoplist_del
3,進階作業
1.編寫下載網頁內容的函式,要求功能是:使用者傳入一個url,函式返回下載頁面的結果。
2.為題目1編寫裝飾器,實現快取網頁內容的功能:
具體:實現下載的頁面存放於檔案中,如果檔案內有值(檔案大小不為0),就優先從檔案中讀取網頁內容,否則,就去下載,然後存到檔案中。
import os
from urllib.request import urlopen
def cache(func):
def inner(*args, **kwargs):
if os.path.getsize('web_cache'):
with open('web_cache', 'rb') as f:
return f.read() #return 之後 程式結束
ret = func(*args, **kwargs)
with open('web_cache','wb') as f:
f.write(b'*********'+ret) #這個地方是為了方便判斷:究竟是在哪讀的。
return ret
return inner
@cache
def get(url):
code = urlopen(url).read()
return code
# {'網址':"檔名"}
ret = get('http://www.baidu.com')
print(ret)
ret = get('http://www.baidu.com')
print(ret)
ret = get('http://www.baidu.com')
print(ret)
輸出結果:
b’
b’*********
b’*********
三,wraps
1,基本知識
from functools import wraps
def wahaha():
'''
一個列印娃哈哈的函式
:return:
'''
print('娃哈哈')
print(wahaha.__name__) #檢視字串格式的函式名
print(wahaha.__doc__) #document
輸出結果:
wahaha
‘’‘
一個列印娃哈哈的函式
’‘’
2,進階
from functools import wraps
def wrapper(func): #func = holiday
@wraps(func)
def inner(*args,**kwargs):
print('在被裝飾的函式執行之前做的事')
ret = func(*args,**kwargs)
print('在被裝飾的函式執行之後做的事')
return ret
return inner
@wrapper #holiday = wrapper(holiday)
def holiday(day):
print('全體放假%s天' % day)
return '好開心'
print(holiday.__name__) #這裡就是wraps的功能
print(holiday.__doc__)
ret = holiday(3)
print(ret)
#因為wraps的功能,是的holiday's name is holiday
輸出結果:
holiday
None
在被裝飾的函式執行之前做的事
全體放假3天
在被裝飾的函式執行之後做的事
好開心
四,裝飾器進階
需求:
帶引數的裝飾器
500個函式
我們如果現在不再需要裝飾器該怎麼辦呢?
note:我們以後還會使用。
import time
FLAGE = True
def timmer_out(flag):
def timmer(func):
def inner(*args,**kwargs):
if flag:
start = time.time()
ret = func(*args,**kwargs)
end = time.time()
print(end-start)
return ret
else:
ret = func(*args, **kwargs)
return ret
return inner
return timmer
# timmer = timmer_out(FLAGE)
@timmer_out(FLAGE)
def wahaha():
time.sleep(0.1)
print('娃哈哈娃哈哈')
@timmer_out(FLAGE)
def erguotou():
time.sleep(0.1)
print('二鍋頭二鍋頭')
wahaha()
erguotou()
輸出結果:
娃哈哈娃哈哈
0.10094165802001953
二鍋頭二鍋頭
0.10095953941345215
多個裝飾器修飾一個函式
#記住執行過程
def wrapper1(func):
def inner1():
print('wrapper1 ,before func')
ret = func()
print('wrapper1 ,after func')
return ret
return inner1
def wrapper2(func):
def inner2():
print('wrapper2 ,before func')
ret = func()
print('wrapper2 ,after func')
return ret
return inner2
def wrapper3(func):
def inner3():
print('wrapper3 ,before func')
ret = func()
print('wrapper3 ,after func')
return ret
return inner3
@wrapper3
@wrapper2
@wrapper1
def f():
print('in f')
return '哈哈哈'
print(f())
輸出結果:
wrapper3 ,before func
wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func
wrapper3 ,after func
哈哈哈