Python裝飾器用法介紹
本文主要介紹Python裝飾器的使用方法及其功能。在Python編程中,裝飾器是一項非常強大的功能,可以節省代碼,同時可以實現多種目的。我們將從以下幾個方面對Python裝飾器進行詳細的闡述。
1、裝飾器是什麼
裝飾器是Python函數的一個重要概念。可以理解為在一個函數外部添加另一個函數,以對原函數進行一些修改或增強功能。裝飾器常常用於日誌打印、性能測試、授權驗證、緩存等場景。
2、裝飾器的基本用法
裝飾器通常以@符號表示,在函數定義前使用。如下所示:
@decorator
def func_name():
pass
其中,decorator為裝飾器函數名,func_name是待裝飾的函數名。在函數運行時,裝飾器會先於函數執行。
下面是一個簡單的裝飾器示例,用於輸出函數執行時間:
import time
def time_cal(func):
def wrapper():
start_time = time.time()
func()
end_time = time.time()
print("花費時間:", end_time - start_time, "秒")
return wrapper
@time_cal
def hello():
print("Hello world!")
上述代碼中,time_cal是計時裝飾器函數,wrapper函數記錄函數開始和結束時間,hello為待裝飾的函數。在@time_cal下,調用hello函數時,會先運行wrapper函數,記錄執行時間,接着調用hello函數輸出”Hello world!”。
緩存裝飾器可以緩存函數的結果,以便在下次調用時直接獲取,而不必重新執行函數。這對於複雜且耗時的函數尤其有用。下面是一個例子:
import functools
def cache(func):
cached = functools.lru_cache(maxsize=None)
@functools.wraps(func)
def wrapper(*args, **kwargs):
return cached(*args, **kwargs)
return wrapper
@cache
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
上述代碼中,cache為緩存裝飾器函數,使用了functools模塊的lru_cache方法。在調用fib函數時,如果已經計算過fib(n)的值,則直接從緩存中獲取;否則,執行fib(n)並將結果緩存起來。
日誌裝飾器可以用於記錄函數的執行情況,比如輸入參數、輸出結果以及程序錯誤等。下面是一個簡單的日誌裝飾器:
def log(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"[INFO]: {func.__name__} start")
result = func(*args, **kwargs)
print(f"[INFO]: {func.__name__} end")
return result
return wrapper
@log
def add(a, b):
return a + b
在使用@log裝飾器後,執行add函數時,會先打印函數名稱和執行開始時間,接着輸出函數結果,並打印執行結束時間。
裝飾器函數可以被替換成一個裝飾器類,使其具有更多的靈活性和可配置性。下面是一個裝飾器類的例子:
class Cache:
def __init__(self, func):
self.func = func
self.cache = {}
def __call__(self, *args):
if args in self.cache:
return self.cache[args]
else:
result = self.func(*args)
self.cache[args] = result
return result
@Cache
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
上述代碼中,Cache類實現了一個簡單的緩存裝飾器,和上一篇緩存裝飾器不同之處在於函數被封裝在類裡面,而不是在函數內。
在Python中,可以同時使用多個裝飾器對函數進行修飾。裝飾器的執行順序與裝飾器定義順序相反。下面是一個雙重裝飾器:
def log(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"[INFO]: {func.__name__} start")
result = func(*args, **kwargs)
print(f"[INFO]: {func.__name__} end")
return result
return wrapper
def cache(func):
@functools.lru_cache(maxsize=None)
@log
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@cache
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
上述代碼中,cache裝飾器使用了另一個裝飾器log,在每次函數執行前打印日誌信息。
裝飾器會改變函數的調用方式,比如參數列表、返回值類型等。為了不影響函數使用,需要在裝飾器中添加functools.wraps(func)語句,保留原函數的元信息。否則,在調用help()等函數時,可能會顯示錯誤的函數簽名。
Python支持裝飾器嵌套,即裝飾器可以使用其他裝飾器,實現更多的功能。但是,裝飾器嵌套深度不能過大,否則會導致代碼可讀性下降和調試難度增加。
對於不需要修改原函數的裝飾器,也可以不添加括號。比如在使用flask框架時,@app.route可以不加括號,直接使用。
本文主要介紹了Python裝飾器的定義、基本用法、應用場景和高級用法,以及注意事項。裝飾器是Python中非常強大的功能,幫助我們實現多種任務,如緩存、日誌、性能等。雖然裝飾器在使用上比較靈活,但需要我們在實踐中多加練習,才能充分發揮它的優勢。