裝飾器(Decorator)本質上是一個返回函數的函數
主要作用是:在不修改原函數代碼的前提下,給函數增加額外的功能
比如:增加業務,日志記錄、權限驗證、執行時間統計、緩存等場景
@my_decorator
def func():pass# 等價于:
def func():pass
func = my_decorator(func)
1、閉包
def outer(x):def inner(y):return x + yreturn inneradd5 = outer(5)
print(add5(3)) # 輸出 8
閉包(Closure)
指一個函數定義在另一個函數內部,并且這個內部函數引用了外部函數的變量。即使外部函數已經返回了,內部函數依然**“記住”**并可以訪問這些變量
就如這里的x
功能
-
保存函數執行時的“上下文”;
-
用于延遲計算或構造回調函數;
-
實現數據隱藏(類似于面向對象中的私有變量);
-
替代某些簡單場景中的類。
2、裝飾器基礎
裝飾器本質上就是閉包的一種應用,用于在不修改函數源代碼的情況下增強函數功能
def decorator(func):def wrapper(*args, **kwargs):start_time = time.time()result = func(*args, **kwargs)stop_time = time.time()print(f'running_time is {stop_time - start_time}')return resultreturn wrapper@decorator # double=decorator(double)
def double(x):time.sleep(1) # 模擬耗時return x*2
double(10)
這里在原本的基礎上增加了(統計函數執行時間)功能
3、保留函數元數據
使用裝飾器后
裝飾器會覆蓋原函數的元數據
使用functools.wraps
裝飾內層函數可保留原函數元數據
import functools
import time# 裝飾器outer
def decorator(func):@functools.wraps(func)def wrapper(*args, **kwargs):'''這里是wrapper的注釋'''start_time = time.time()result = func(*args, **kwargs)stop_time = time.time()print(f'running_time is {stop_time - start_time}')return resultreturn wrapper
@decorator # double=decorator(double)
def double(x):'''這里是doubled的注釋'''time.sleep(1) # 模擬耗時return x*2
double(10)
print(double.__name__)
print(double.__doc__)
4、帶參數的裝飾器
需要使用三層函數來實現。最外層函數接收裝飾器參數,中間層函數接收原函數,最內層函數完成對原函數的調用以及附加功能。
def timer(time_consume):def decorator(func):@functools.wraps(func)def wrapper(*args, **kwargs):start_time = time.time()result = func(*args, **kwargs)stop_time = time.time()if (stop_time - start_time>time_consume):print(f'running is {stop_time - start_time}')print(f'{func.__name__} is longer')return resultreturn wrapperreturn decorator
@timer(0.8) # double=timer(0.8)(double)
def double(x):time.sleep(1) # 模擬耗時return x*2
double(10)