15 Python學習之裝飾器
阿新 • • 發佈:2020-08-06
裝飾器
裝飾器:在不改變源函式的程式碼及呼叫方式的前提下,為其增加新的功能,裝飾器就是一個函式,他的本質是閉包
裝飾器開放封閉的原則:
開放:對程式碼的擴充套件開放
封閉:對原始碼的修改是封閉的
被裝飾函式無引數,無返回值
例1:
import time def timer(func): def inner(): start_time = time.time() func() end_time = time.time() print(f'裝飾器列印執行時間為:{round(end_time - start_time, 5)}') return inner # 閉包,返回內層函式的引用 # show_info = timer(show_info)第一個show_info是一個新的變數,第二個show_info的函式名,@timer是show_info = timer(show_info)的簡寫,官方叫做語法糖 @timer def show_info(): print(f"我的姓名是:張三") time.sleep(2) show_info()
執行結果:
我的姓名是:張三
裝飾器列印執行時間為:2.00051
被裝飾函式有返回值
被裝飾函式有返回值,那麼在設計裝飾器的時候,就應該有變數進行接收,然後再將該返回值返回給呼叫者
例1:
import time def timer(func): def inner(): start_time = time.time() inner_ret = func() # 呼叫原函式並接受返回值 end_time = time.time() print(f'裝飾器列印執行時間為:{round(end_time - start_time, 5)}') return inner_ret # 將呼叫原函式的返回值返回給呼叫者 return inner # 閉包,返回內層函式的引用 @timer # show_info = timer(show_info)第一個show_info是一個新的變數,第二個show_info的函式名,@timer是show_info = timer(show_info)的簡寫,官方叫做語法糖 def show_info(): print(f"我的姓名是:張三") time.sleep(2) return 'show_info函式的返回值' ret = show_info() # ret接受的是inner的返回值inner_ret print(ret)
我的姓名是:張三
裝飾器列印執行時間為:2.00168
show_info函式的返回值
被裝飾函式有引數
被裝飾函式有引數,由於實際呼叫的時候,掉的是閉包中的內部函式,所以內部函式相應的也要設計成跟原函式一樣的帶引數
例1:
import time def timer(func): def inner(name): # 設計時需要新增引數 start_time = time.time() inner_ret = func(name) # 呼叫原函式indxe,傳入引數並接受返回值 end_time = time.time() print(f'裝飾器列印執行時間為:{round(end_time - start_time, 5)}') return inner_ret # 將呼叫原函式的返回值返回給呼叫者 return inner # 閉包,返回內層函式的引用 @timer # show_info = timer(show_info)第一個show_info是一個新的變數,第二個show_info的函式名,@timer是show_info= timer(show_info)的簡寫,官方叫做語法糖 def show_info(name): print(f"我的姓名是:{name}") time.sleep(2) return 'show_info函式的返回值' ret = show_info('張三') # 相當於ret = inner('張三') print(ret)
我的姓名是:張三
裝飾器列印執行時間為:2.00031
show_info函式的返回值
標準裝飾器
由於被裝飾函式的引數個數不確定,所以我們在設計裝飾器時,內部函式的引數個數就無法確定,因此要設計成不定長的形式
例1:
import time
def timer(func):
def inner(*args, **kwargs): # 設計時需要新增引數
start_time = time.time()
inner_ret = func(*args, **kwargs) # 呼叫原函式indxe,傳入引數並接受返回值
end_time = time.time()
print(f'裝飾器列印執行時間為:{round(end_time - start_time, 5)}')
return inner_ret # 將呼叫原函式的返回值返回給呼叫者
return inner # 閉包,返回內層函式的引用
@timer # show_info = timer(show_info)第一個show_info是一個新的變數,第二個show_info的函式名,@timer是show_info= timer(show_info)的簡寫,官方叫做語法糖
def show_info(name, age):
print(f"我的姓名是:{name}, 今年{age}歲")
time.sleep(2)
return 'show_info函式的返回值'
ret = show_info('張三', 25)
print(ret)
我的姓名是:張三, 今年25歲
裝飾器列印執行時間為:2.0017
show_info函式的返回值
特別注意
在標準裝飾器中,def inner(*args, **kwargs):
中的 *
在函式 定義 的時候是將傳入函式的引數聚合成一個元素,在 呼叫函式 inner_ret = func(*args, **kwargs)
的時候 *
的作用是將一個可迭代的物件進行打散,即將變數 args或kwargs
打散,拆分成一個個要傳入的實參
標準裝飾器模板:
def decorator(real_func_name):
def inner(*args, **kwwargs):
'''呼叫裝飾器訪問函式前要執行的操作'''
ret = real_func_name(*args, **kwwargs)
'''呼叫裝飾器訪問函式後要執行的操作'''
return ret
return inner
裝飾器的應用
裝飾器一般用於登入驗證和日誌
例1:
def login():
name = input('請輸入使用者名稱:')
pwd = input('請輸入密碼:')
login_status['name'] = name
if pwd == '123456':
login_status['status'] = True
return 1
else:
return 0
login_status = {
'name': None,
'status': False
}
def decorator(func_name):
def inner(*args, **kwargs):
if login_status['status']:
ret = func_name(*args, **kwargs)
return ret
else:
ret = login()
if ret:
ret = func_name()
return ret
else:
print('登入失敗')
return inner
@decorator
def index():
print("index頁面")
@decorator
def logger():
print("logger頁面")
# 只有登入成功後才會執行函式,並列印資訊
index()
logger()
請輸入使用者名稱:張三
請輸入密碼:123456
index頁面
logger頁面