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中非常強大的功能,幫助我們實現多種任務,如緩存、日誌、性能等。雖然裝飾器在使用上比較靈活,但需要我們在實踐中多加練習,才能充分發揮它的優勢。