裝飾器本質上是一個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中文網其他相關文章!

Python更易學且易用,C 則更強大但複雜。 1.Python語法簡潔,適合初學者,動態類型和自動內存管理使其易用,但可能導致運行時錯誤。 2.C 提供低級控制和高級特性,適合高性能應用,但學習門檻高,需手動管理內存和類型安全。

Python和C 在内存管理和控制方面的差异显著。1.Python使用自动内存管理,基于引用计数和垃圾回收,简化了程序员的工作。2.C 则要求手动管理内存,提供更多控制权但增加了复杂性和出错风险。选择哪种语言应基于项目需求和团队技术栈。

Python在科學計算中的應用包括數據分析、機器學習、數值模擬和可視化。 1.Numpy提供高效的多維數組和數學函數。 2.SciPy擴展Numpy功能,提供優化和線性代數工具。 3.Pandas用於數據處理和分析。 4.Matplotlib用於生成各種圖表和可視化結果。

選擇Python還是C 取決於項目需求:1)Python適合快速開發、數據科學和腳本編寫,因其簡潔語法和豐富庫;2)C 適用於需要高性能和底層控制的場景,如係統編程和遊戲開發,因其編譯型和手動內存管理。

Python在數據科學和機器學習中的應用廣泛,主要依賴於其簡潔性和強大的庫生態系統。 1)Pandas用於數據處理和分析,2)Numpy提供高效的數值計算,3)Scikit-learn用於機器學習模型構建和優化,這些庫讓Python成為數據科學和機器學習的理想工具。

每天學習Python兩個小時是否足夠?這取決於你的目標和學習方法。 1)制定清晰的學習計劃,2)選擇合適的學習資源和方法,3)動手實踐和復習鞏固,可以在這段時間內逐步掌握Python的基本知識和高級功能。

Python在Web開發中的關鍵應用包括使用Django和Flask框架、API開發、數據分析與可視化、機器學習與AI、以及性能優化。 1.Django和Flask框架:Django適合快速開發複雜應用,Flask適用於小型或高度自定義項目。 2.API開發:使用Flask或DjangoRESTFramework構建RESTfulAPI。 3.數據分析與可視化:利用Python處理數據並通過Web界面展示。 4.機器學習與AI:Python用於構建智能Web應用。 5.性能優化:通過異步編程、緩存和代碼優

Python在開發效率上優於C ,但C 在執行性能上更高。 1.Python的簡潔語法和豐富庫提高開發效率。 2.C 的編譯型特性和硬件控制提升執行性能。選擇時需根據項目需求權衡開發速度與執行效率。


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境

記事本++7.3.1
好用且免費的程式碼編輯器

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

Dreamweaver CS6
視覺化網頁開發工具