W3Cschool
恭喜您成為首批注冊用戶
獲得88經驗值獎勵
裝飾器(decorators)是 一種設計模式,之所以被稱為裝飾器,是因為其本質是對一個函數或者對象進行了"修飾",裝飾器可以在你進入對象或者函數前后進行一些操作,可以在不修改原來的代碼的情況下讓函數的行為發(fā)生改變。
面向切面編程(AOP),是指某些業(yè)務流程具有相似性,只有部分核心代碼有差異,我們可以把相同部分的代碼提取出來,不同的代碼(切片)另外實現,這就是面向切面編程。在 java 的 spring 中,這是一種很重要的技術,而 python 也有類似的實現方式,最常見的就是裝飾器。
裝飾器允許你動態(tài)地修改函數或類的行為。它本質上是一個函數,可以接受一個函數作為參數,并返回一個新的函數或者修改原來的函數。
裝飾器雖然是一個函數,但它更常見的使用方式是使用 ?@decorator_name
? 來應用在函數或方法上。
例如:
from flask import Flask
app =Flask(__name__)
?
# app.route就是一個Flask內置的裝飾器
@app.route("index")
def index():
return "hello"
Python 還提供了一些內置的裝飾器,比如 ?@staticmethod
? 和 ?@classmethod
?,用于定義靜態(tài)方法和類方法。
import time
def runtime(func):#定義一個裝飾器函數叫runtime 他接受一個函數func作為參數
def wrapper(*args, **kwargs): # 包裝函數wrapper,這里接受所有參數
# 這里是在調用原始函數前添加的新功能
starttime= time.time() #獲取開始執(zhí)行的時間
# 在包裝函數中調用原始函數(可以不調用)
result = func(*args, **kwargs) # 函數傳遞的參數為包裝函數接受的所有參數
# 這里是在調用原始函數后添加的新功能
endtime= time.time() #獲取結束執(zhí)行的時間
?
print(f"函數{func.__name__}運行時間:{endtime-starttime}秒") #輸出函數運行的時間
?
return result # 返回函數運行的結果
return wrapper
?
# 使用裝飾器裝飾一個函數,現在運行這個函數時,會運行裝飾器的代碼,然后再由裝飾器運行這個func
# (如果裝飾器不調用這個函數,而是調用別的函數,就可以替換掉原有函數的功能)
@runtime
def sleepfunc(arg1, arg2):
time.sleep(2)
return arg1 + arg2
?
print(sleepfunc(1, 2))
函數sleepfunc運行時間:2.005006790161133秒
3
解析:?runtime
?是一個裝飾器函數,它接受一個函數 ?func
? 作為參數,并返回一個內部函數 ?wrapper
?,在 ?wrapper
? 函數內部,你可以執(zhí)行一些額外的操作,然后調用原始函數 ?func
?,并返回其結果。
@runtime
? 前綴在 ?sleepfunc
? 定義前,Python會自動將 ?sleepfunc
? 作為參數傳遞給 ?runtime
?,然后將返回的 ?wrapper
? 函數替換掉原來的 ?sleepfunc
?。裝飾器通過 ?@
? 符號應用在函數定義之前,例如:
@time_logger
def target_function():
pass
等同于:
def target_function():
pass
target_function = time_logger(target_function)
這會將 ?target_function
? 函數傳遞給 ?decorator
? 裝飾器,并將返回的函數重新賦值給 ?target_function
?。從而,每次調用 ?target_function
? 時,實際上是調用了經過裝飾器處理后的函數。
通過裝飾器,開發(fā)者可以在保持代碼整潔的同時,靈活且高效地擴展程序的功能。
裝飾器函數也可以接受參數,但是需要在原有的裝飾器外再套一層裝飾器。
例如:
import time
?
?
?
def runtime(n:int):#定義一個裝飾裝飾器的裝飾函數,他可以接受參數
def decorator(func):#定義一個裝飾器函數,接受一個函數func作為參數
def wrapper(*args, **kwargs): # 包裝函數wrapper,這里接受所有參數
# 這里是在調用原始函數前添加的新功能
starttime= time.time() #獲取開始執(zhí)行的時間
# 在包裝函數中調用原始函數(可以不調用)
result = func(*args, **kwargs) # 函數傳遞的參數為包裝函數接受的所有參數
# 這里是在調用原始函數后添加的新功能
endtime= time.time() #獲取結束執(zhí)行的時間
?
print(f"函數{func.__name__}運行時間:{endtime-starttime}秒") #輸出函數運行的時間
print("裝飾器傳遞過來的參數為:",n)
?
return result # 返回函數運行的結果
return wrapper # 返回包裝函數
return decorator # 返回裝飾器函數
?
?
# 使用裝飾器裝飾一個函數,現在運行這個函數時,會運行裝飾器的代碼,然后再由裝飾器運行這個func
# (如果裝飾器不調用這個函數,而是調用別的函數,就可以替換掉原有函數的功能)
@runtime(1)
def sleepfunc(arg1, arg2):
time.sleep(2)
return arg1 + arg2
?
print(sleepfunc(1, 2))
運行結果為:
函數sleepfunc運行時間:2.000138521194458秒
裝飾器傳遞過來的參數為: 1
3
以上代碼中 ?runtime
?函數是一個帶參數的裝飾器,它接受一個整數參數 ?n
?,然后返回一個裝飾器函數。該裝飾器函數內部定義了 ?wrapper
? 函數,我們可以在裝飾器內部獲取到這個參數n(內層函數可以獲取到外層函數的變量),上面只是簡單的打印了這個參數,我們也可以讓這個參數參與到代碼運行中。
比如?flask
?的?@app.route
?就可以接受參數來決定該方法是?get
?還是?post
?。
除了函數裝飾器,Python 還支持類裝飾器。類裝飾器是包含 ?call
? 方法的類,它接受一個函數作為參數,并返回一個新的函數。
class DecoratorClass:
def __init__(self, func):
self.func = func
?
def __call__(self, *args, **kwargs):
# 在調用原始函數之前/之后執(zhí)行的代碼
result = self.func(*args, **kwargs)
# 在調用原始函數之后執(zhí)行的代碼
return result
@DecoratorClass
def my_function():
pass
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯系方式:
更多建議: