一、裝飾器
1、什么是裝飾器?
裝飾:裝飾、修飾
器:工具
裝飾器:裝飾的工具
(*****)“開放封閉”:裝飾器必須要遵循“開放封閉”原則:
開放:對函式功能的添加是開放的
封閉:對函式功能的修改是封閉的
2、裝飾器的作用?
在不修改被裝飾物件源代碼與呼叫方式的前提下添加新的功能,
裝飾器必須遵循的兩個原則:
不修改被裝飾物件源代碼
不修改被裝飾物件的呼叫方式
ps:
被裝飾物件指的是 ---> 需要添加功能的(函式)
裝飾器指的是 ---> 被裝飾物件添加的新功能的(函式)
3、為什么要使用裝飾器?
可以解決代碼榮譽問題,提高代碼的可擴展性
4、怎么使用裝飾器?
撰寫裝飾器:
通過閉包函式來實作裝飾器
裝飾器的應用:
1、統計時間
2、登錄認證
例子:
需求:需要統計一下下載電影的時間
方案一:函式呼叫(適合少次使用)
import time
def download_movie():
print("開始下載電影...")
# 模擬電影下載時間為3秒
time.sleep(3)
print("電影下載成功!")
start_time = time.time() # 獲取當前時間戳
download_movie()
end_time = time.time() # 獲取當前時間戳
print(f"消耗時間:{end_time - start_time}")
問題1:如果有多個被裝飾物件,需要寫多次統計時間的代碼,導致代碼冗余,于是有了方案二,
方案二:使用裝飾器(適合多次呼叫,呼叫時直接在閉包函式內傳入所需要使用裝飾器的函式名稱)
import time
def download_movie():
print("開始下載電影...")
# 模擬電影下載時間為3秒
time.sleep(3)
print("電影下載成功!")
# 模擬多個被裝飾物件
def func1():
pass
# 模擬多個被裝飾物件
def func2():
pass
# 裝飾器:初級版
def time_record(func):
def inner():
# 獲取當前時間戳
start_time = time.time()
func()
# 獲取當前時間戳
end_time = time.time()
print(f"消耗時間:{end_time - start_time}")
return inner
download_movie = time_record(download_movie)
download_movie()
問題2:如果被裝飾物件有回傳值,有引數而且有多個引數,于是有了方案三,
方案三:方案二的代碼優化,使用*args, **kwargs接收所有引數(形參,關鍵字引數等)import time
def download_movie(*args, **kwargs):
print("開始下載電影...")
# 模擬電影下載時間
time.sleep(3)
print("電影下載成功!")
return "movie.mp4"
# 裝飾器最終版
def time_record(func):
def inner(*args, **kwargs): # *args **kwargs接收所有引數(形參,關鍵字引數等)
# 獲取當前時間戳
start_time = time.time()
# 將被裝飾物件需要接收的人以引數,原封不動的傳給func(被修飾物件)
res = func(*args, **kwargs) #此處的fanc為被修飾物件download_movie()
# 獲取當前時間戳
end_time = time.time()
# 統計結束,列印統計時間
print(f"消耗時間:{end_time - start_time}")
return res
return inner
# 這里的download_movie是inner()的回傳值
download_movie = time_record(download_movie)
# download_movie() ---> inner() ,可傳入任意引數,若傳入引數,download_movie()函式需要修改代碼塊,否則不列印或者不執行傳入引數
download_movie()
方案三完美的解決了方案一和方案二遺留下的問題,此處的裝飾器可以作為所有裝飾器的模板
(*****)裝飾器模板(記牢)
def wrapper(func): def inner(*args, **kwargs): # *args **kwargs接收所有引數(形參,關鍵字引數等) # 呼叫被裝飾物件,得到被裝飾物件的回傳值res res = func(*args, **kwargs) return res return inner
裝飾器簡例:
def wrapper(func):
def inner(*args, **kwargs):
'''
在此處可以添加新添加的功能代碼塊
'''
# 呼叫被裝飾物件,得到被裝飾物件的回傳值res
res = func(*args, **kwargs)
'''
在此處也可以添加新添加的功能代碼塊
'''
return res
return inner
def func1():
print("hello")
func1 = wrapper(func1)
func1()
代碼執行順序:
def為定義函式,不執行
先執行同級代碼,再執行下級函式體代碼
二、裝飾器語法糖
裝飾器的語法糖,是屬于裝飾器的(語法糖是裝飾器內置的,可以參考所有的語法糖)
@裝飾器名字 裝飾器的語法糖
注意:在使用裝飾器語法糖時,裝飾器必須定義在被裝飾物件之上
例子:統計函式執行時間
不使用裝飾器語法糖:
import time
# func函式執行三秒
def func():
time.sleep(3)
# 裝飾器:統計函式執行時間
def wrapper(func): # func被裝飾物件
def inner(*args, **kwargs): # *args, **kwargs是被裝飾物件的引數
# 呼叫前增加新功能
start_time = time.time()
res = func(*args, **kwargs)
# 呼叫前增加新功能
end_time = time.time()
print(f"程式執行時間為:{end_time - start_time}秒")
return res # 呼叫被裝飾物件,接識訓傳值
return inner
# 不使用裝飾器語法糖
func = wrapper(func)
func()
使用裝飾器語法糖:
import time
# 裝飾器:統計函式執行時間
def wrapper(func): # func被裝飾物件
def inner(*args, **kwargs): # *args, **kwargs是被裝飾物件的引數
# 呼叫前增加新功能
start_time = time.time()
res = func(*args, **kwargs)
# 呼叫前增加新功能
end_time = time.time()
print(f"程式執行時間為:{end_time - start_time}秒")
return res # 呼叫被裝飾物件,接識訓傳值
return inner
# 使用裝飾器語法糖:使用裝飾器語法糖時,裝飾器必須定義在被裝飾物件之上
@wrapper # @wrapper 就等于---> func = wrapper(func)
# func函式執行三秒
def func():
time.sleep(3)
func() # 因為語法糖可直接呼叫
三、裝飾器練習題
撰寫一個裝飾器,為多個函式加上認證的功能(用戶的賬號密碼來源于檔案),要求登錄成功一次,后續的函式都無需再輸入用戶名密碼
可寫完對照
# 定義一個字典來做判斷
user_info = {
"user" : None, # username與user_info["user"]來判斷是否已登錄用戶
}
# 登錄功能:
def login():
# 判斷用戶沒有登錄時,執行
# 登陸功能
print("請先登錄")
username = input("請輸入你的用戶名:").strip()
password = input("請輸入您的密碼:").strip()
# 打開密碼表,對比賬戶密碼是否正確
with open("dir/passwd.txt", "r", encoding="utf-8") as f:
for line in f:
# print(line)
name, pwd = line.strip("\n").split(":") # 得到[tank, 123]
if username == name and password == pwd:
print("登陸成功!")
user_info["user"] = username
else:
print("登錄失敗")
# 登錄認證裝飾器:
def login_auth(func):
def inner(*args, **kwargs):
# 登錄認證功能
# 如果已經登錄,將被裝飾物件直接呼叫并回傳
if user_info.get("user"):
res = func(*args, **kwargs)
return res
# 如果沒有登錄,執行登錄功能
else:
login() # 呼叫login()函式進行登錄
return inner
# func1、2、3都需要先登錄才能使用,若登陸一次,后續就不需要再次登錄
# 登陸之后可以使用的功能1
@login_auth
def func1():
print("from func1")
pass
# 登陸之后可以使用的功能2
@login_auth
def func2():
print("from func2")
pass
# 登陸之后可以使用的功能3
@login_auth
def func3():
print("from func3")
pass
# 執行環節
while True:
func1()
input("延遲操作")
func2()
func3()
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/168449.html
標籤:Python
下一篇:Python之裝飾器2
