首頁 後端開發 Python教學 Python裝飾器詳細介紹

Python裝飾器詳細介紹

Jun 18, 2020 pm 05:40 PM
python 裝飾器

裝飾器本質上是一個Python函數,它可以讓其他函數在不需要做任何程式碼變動的前提下增加額外功能,裝飾器的回傳值也是一個函數物件.

Python裝飾器詳細介紹

常用於有切面需求的場景,例如:插入日誌、效能測試、交易處理、快取、權限校驗等場景。裝飾器是解決這類問題的絕佳設計,有了裝飾器,我們就可以抽離出大量與函數功能本身無關的雷同程式碼並繼續重複使用。

先來看一個簡單範例:

def now():
    print('2017_7_29')
登入後複製

現在有一個新的需求,希望可以記錄下函數的執行日誌,於是在程式碼中加入日誌程式碼:

def now():
    print('2017_7_29')
    logging.warn("running")
登入後複製

假設有類似的多個需求,怎麼做?再寫一個logging在now函數裡?這樣就造成大量雷同的程式碼,為了減少重複寫程式碼,我們可以這樣做,重新定義一個函數:專門處理日誌,日誌處理完之後再執行真正的業務程式碼.

def use_logging(func):     
    logging.warn("%s is running" % func.__name__)     
    func()  
def now():     
    print('2017_7_29')    
use_logging(now)
登入後複製

在實作,邏輯上不難, 但是這樣的話,我們每次都要將一個函數當作參數傳遞給日誌函數。而且這種方式已經破壞了原有的程式碼邏輯結構,之前執行業務邏輯時,執行運行now(),但是現在不得不改成use_logging(now)。

那麼有沒有更好的方式的呢?當然有,答案就是裝飾器。

首先要明白函數也是一個對象,而且函數物件可以被賦值給變數,所以,透過變數也能呼叫該函數。例如:

(=
登入後複製

 簡單裝飾器

#本質上,decorator就是回傳函數的高階函數。所以,我們要定義一個能列印日誌的decorator,可以定義如下:

def log(func):
    def wrapper(*args,**kw):
        print('call %s():'%func.__name__)
        return func(*args,**kw)
    return wrapper
# 由于log()是一个decorator,返回一个函数,所以,原来的now()函数仍然存在,
# 只是现在同名的now变量指向了新的函数,于是调用now()将执行新函数,即在log()函数中返回的wrapper()函数。
# wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。
# 在wrapper()函数内,首先打印日志,再紧接着调用原始函数。
登入後複製

上面的log,因為它是一個decorator,所以接受一個函數作為參數,並傳回一個函數.現在執行:

now = log(now)
now()
登入後複製
输出结果:
call now():
2017_7_28
登入後複製

函數log就是裝飾器,它把執行真正業務方法的func包裹在函數裡面,看起來像now被log裝飾了。在這個例子中,函數進入時 ,被稱為一個橫切面(Aspect),這種程式設計方式被稱為面向切面的程式設計(Aspect-Oriented Programming)。

使用語法糖:

@logdef now():
    print('2017_7_28')
登入後複製

@符號是裝飾器的語法糖,在定義函數的時候使用,避免再一次賦值運算

這樣我們就可以省去now = log(now)這句話了,直接呼叫now()即可得到想要的結果。如果我們有其他的類似函數,我們可以繼續呼叫裝飾器來修飾函數,而不用重複修改函數或增加新的封裝。這樣,我們就提高了程式的可重複利用性,並增加了程式的可讀性。

裝飾器在Python使用如此方便都要歸因於Python的函數能像普通的物件一樣能作為參數傳遞給其他函數,可以被賦值給其他變量,可以作為返回值,可以被定義在另外一個函數內。

有參數的裝飾器:

#如果decorator本身需要傳入參數,那就需要寫一個傳回decorator的高階函數,寫出來會複雜一點。例如,要自訂log的文字: 

def log(text):
    def decorator(func):
            def wrapper(*args,**kw):
                        print('%s %s()'%(text,func.__name__))
                        return func(*args,**kw)        
            return wrapper    
     return decorator
登入後複製

 這個3層嵌套的decorator用法如下:

@log(()
now()
登入後複製

等價於

<span style="color: #000000;">now = log('goal')(now)<br># 首先执行log('execute'),返回的是decorator函数,再调用返回的函数,参数是now函数,返回值最终是wrapper函数<br>now()</span>
登入後複製

因為我們講了函數也是對象,它有__name__等屬性,但你去看經過decorator裝飾之後的函數,它們的__name__已經從原來的'now'變成了'wrapper'

print(now.__name__)# wrapper
登入後複製

因為傳回的那個wrapper()函數名稱就是'wrapper',所以,需要把原始函數的__name__等屬性複製到wrapper()函數中,否則,有些依賴函數簽名的程式碼執行就會出錯。

不需要寫wrapper.__name__ = func.__name__這樣的程式碼,Python內建的functools.wraps就是做這個事的,所以,一個完整的decorator的寫法如下:

import functools

def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper
登入後複製
import functools

def log(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator
登入後複製

 類別裝飾器:

再來看看類別裝飾器,相較於函數裝飾器,類別裝飾器具有靈活度大、高內聚、封裝性等優點。使用類別裝飾器也可以依賴類別內部的__call__方法,當使用@ 形式將裝飾器附加到函數上時,就會呼叫此方法

import time

class Foo(object):     
    def __init__(self, func):     
        self._func = func  
    
    def __call__(self):     
        print ('class decorator runing')     
        self._func()     
        print ('class decorator ending')  

@Foo 
def now():     
    print (time.strftime('%Y-%m-%d',time.localtime(time.time())))  
    
now()
登入後複製

總結:

概括的講,裝飾器的作用就是為已經存在的物件添加額外的功能。  

同時在物件導向(OOP)的設計模式中,decorator被稱為裝飾模式。 OOP的裝飾模式需要透過繼承和組合來實現,而Python除了能支援OOP的decorator外,直接從語法層次支援decorator。 Python的decorator可以用函數實現,也可以用類別實作。

更多相關知識請關注python影片教學欄位

以上是Python裝飾器詳細介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

PHP和Python:解釋了不同的範例 PHP和Python:解釋了不同的範例 Apr 18, 2025 am 12:26 AM

PHP主要是過程式編程,但也支持面向對象編程(OOP);Python支持多種範式,包括OOP、函數式和過程式編程。 PHP適合web開發,Python適用於多種應用,如數據分析和機器學習。

在PHP和Python之間進行選擇:指南 在PHP和Python之間進行選擇:指南 Apr 18, 2025 am 12:24 AM

PHP適合網頁開發和快速原型開發,Python適用於數據科學和機器學習。 1.PHP用於動態網頁開發,語法簡單,適合快速開發。 2.Python語法簡潔,適用於多領域,庫生態系統強大。

Python vs. JavaScript:學習曲線和易用性 Python vs. JavaScript:學習曲線和易用性 Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

PHP和Python:深入了解他們的歷史 PHP和Python:深入了解他們的歷史 Apr 18, 2025 am 12:25 AM

PHP起源於1994年,由RasmusLerdorf開發,最初用於跟踪網站訪問者,逐漸演變為服務器端腳本語言,廣泛應用於網頁開發。 Python由GuidovanRossum於1980年代末開發,1991年首次發布,強調代碼可讀性和簡潔性,適用於科學計算、數據分析等領域。

vs code 可以在 Windows 8 中運行嗎 vs code 可以在 Windows 8 中運行嗎 Apr 15, 2025 pm 07:24 PM

VS Code可以在Windows 8上運行,但體驗可能不佳。首先確保系統已更新到最新補丁,然後下載與系統架構匹配的VS Code安裝包,按照提示安裝。安裝後,注意某些擴展程序可能與Windows 8不兼容,需要尋找替代擴展或在虛擬機中使用更新的Windows系統。安裝必要的擴展,檢查是否正常工作。儘管VS Code在Windows 8上可行,但建議升級到更新的Windows系統以獲得更好的開發體驗和安全保障。

visual studio code 可以用於 python 嗎 visual studio code 可以用於 python 嗎 Apr 15, 2025 pm 08:18 PM

VS Code 可用於編寫 Python,並提供許多功能,使其成為開發 Python 應用程序的理想工具。它允許用戶:安裝 Python 擴展,以獲得代碼補全、語法高亮和調試等功能。使用調試器逐步跟踪代碼,查找和修復錯誤。集成 Git,進行版本控制。使用代碼格式化工具,保持代碼一致性。使用 Linting 工具,提前發現潛在問題。

notepad 怎麼運行python notepad 怎麼運行python Apr 16, 2025 pm 07:33 PM

在 Notepad 中運行 Python 代碼需要安裝 Python 可執行文件和 NppExec 插件。安裝 Python 並為其添加 PATH 後,在 NppExec 插件中配置命令為“python”、參數為“{CURRENT_DIRECTORY}{FILE_NAME}”,即可在 Notepad 中通過快捷鍵“F6”運行 Python 代碼。

vscode 擴展是否是惡意的 vscode 擴展是否是惡意的 Apr 15, 2025 pm 07:57 PM

VS Code 擴展存在惡意風險,例如隱藏惡意代碼、利用漏洞、偽裝成合法擴展。識別惡意擴展的方法包括:檢查發布者、閱讀評論、檢查代碼、謹慎安裝。安全措施還包括:安全意識、良好習慣、定期更新和殺毒軟件。

See all articles