Python裝飾器用法介紹

P8QAD 數碼 4

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

回復

共1條回復 我來回復
  • 暫無回復內容