一文了解 Python 中的裝飾器
theme: smartblue highlight: a11y-light
Offer 駕到,掘友接招!我正在參與2022春招打卡活動,點擊查看活動詳情。
前言
本文將帶你學習裝飾器在 Python 中的工作原理,如果在函數和類中使用裝飾器,如何利用裝飾器避免代碼重複(DRY 原則,Don’t Repeat Yourself )。
Python 中的裝飾器是什麼
裝飾器在 Python中是一個非常強大和有用的工具,因為它允許程序員修改函數或類的行為。裝飾器允許我們包裝另一個函數,以擴展包裝函數的行為,而無需修改基礎函數定義。這也被稱為元編程,因為程序本身在程序運行時會嘗試修改自身的另一部分。
裝飾器是語法糖: 在代碼中利用更簡潔流暢的語法實現更為複雜的功能。
我們知道,Python 一切皆對象。這意味着 Python 中的函數可以用作參數或作為參數傳遞。一等函數的屬性:
- 函數是 Object 類型的實例。
- 可以將函數存儲在變量中。
- 可以將該函數作為參數傳遞給另一個函數。
- 可以從函數中返回函數。
- 可以將它們存儲在數據結構中,例如哈希表,列表等。
讓我們看一個這樣的例子。
```python def hello(): print('Welcome to Python Decorator!')
another_hello = hello() another_hello
Welcome to Python Decorator!
```
定義了一個 hello()
函數,然後將 hello 函數分配給 another_hello 變量,然後調用這個變量,得到的結果是 hello 函數被執行。
既然 Python 中的函數是對象,那麼除了可以簡單的調用之外,就可以把函數作為對象傳遞給另一個函數。
```python def print_welcome(): print('Welcome to Python Decorator!')
def print_hello(func): def inner(): print('Hello!') func() return inner
decorated = print_hello(print_welcome) decorated()
Hello!
Welcome to Python Decorator!
```
語法糖
但是,上面的代碼使用了內部函數我們可以通過簡單地用裝飾器函數 print_hello()
來裝飾 print_welcome()
函數。
裝飾器可以簡化我們的操作。功能完全一樣,但它的代碼更簡潔。即通過 @
符號簡化裝飾器的使用,如下所示:
```python def print_hello(func): def inner(): print('Hello!') func() return inner
@print_hello def print_welcome(): print('Welcome to Python Decorator!')
print_welcome()
Hello!
Welcome to Python Decorator!
```
通過這樣做,我們能夠消除將一個函數顯式傳遞到另一個函數中的使用。Python 裝飾器隱式處理這一點。
使用 Python 裝飾器修改函數行為
使用 Python 裝飾器對函數進行計時
為了演示它們的實用性,讓我們構建一個函數,該函數採用另一個函數並對其執行進行計時。在這裏,使用裝飾器的好處是它允許我們遵循 DRY 編程原則。
裝飾器可用於測量函數執行所需的時間。 如果你定義一個簡單的睡眠函數,以計算該函數的運行時。
```python import time
def timeit(func): def timed(): start = time.time() result = func() end = time.time() print(f'Program took {(end - start) * 1000}s to run') return result return timed
@timeit def print_welcome(): print('Welcome to Python Decorator!')
print_welcome()
Welcome to Python Decorator!
Program took 0.0s to run
```
分析一下上面的代碼:
- 定義了一個函數
timeit()
接受另一個函數 - 該函數還有另一個內部函數
timed()
- 函數跟蹤開始時間,執行修飾函數,跟蹤結束時間,計算差值並返回結果
- 最後,外層函數返回內層函數
當我們將此裝飾器函數應用於我們的函數 print_welcome()
時,首先會返回歡迎問候語,然後顯示執行時間。
使用 Python 裝飾器將有用信息記錄到終端
與上面的例子類似,我們可以在程序運行時使用裝飾器將有用的信息打印到終端。例如,我們可能想知道正在運行哪個函數以及當前時間。也可以使用裝飾器傳遞到日誌文件:
```python from datetime import datetime def log_info(func): def inner(): print(f'Starting run at {datetime.now()}') print(f'Running {func.name}') func() return inner
@log_info def print_welcome(): print('Welcome to Python Decorator!')
print_welcome()
Starting run at 2022-03-27 23:26:38.473310
Running print_welcome
Welcome to Python Decorator!
```
在上面的示例中,在運行函數之前,我們的裝飾器打印當前日期和時間以及將要運行的函數的名稱。如果您正在運行較長的腳本,並且只是想知道程序的位置,這可能很有用。
Web app 中使用的裝飾器
讓我們以 Web 應用程序的用例為例。當您在 Flask 中構建 Web 應用程序時,您總是會編寫 url 路由。 每條路線都是 Web 應用程序中的特定頁面。 打開頁面 /about
可能會調用 about_page()
方法。
python
@app.route("/about")
def about_page():
return "Website about nachos"
將參數傳遞給 Python 裝飾器
到目前為止,您已經學習瞭如何創建一些有用的 Python 裝飾器。然而,這些裝飾器都沒有傳入參數。在本節中,您將學習如何創建接受參數的 Python 裝飾器。
為此,我們將允許在 Python 語法魔術解壓縮。使用 func_name(*args,**kwargs)
,它將解壓縮所有參數和所有關鍵字參數。通過在裝飾器中使用它,可以確保裝飾器將接受任意數量的參數或關鍵字參數。這使得它們在重複使用時更加實用。
```python def print_function_name(func): def inner(args, kwargs): print(f'Running {func.name}...') return func(args, **kwargs) return inner
@print_function_name def add_nums(a, b): print(a + b)
add_nums(1, 2)
Running add_nums...
3
```
上述方法的美妙之處在於它同時接受位置和關鍵字參數。因此,即使我們以以下任何格式執行該函數,該函數也將運行:
-
add_nums(1024, 2020)
-
add_nums(1024, b = 2021)
-
add_nums(a = 1024, b = 2222)
使用多個 Python 裝飾器
關於 Python 裝飾器的一個有趣的方式是:可以同時使用多個裝飾器。這意味着您可以將多個裝飾器應用於單個函數。為了理解這一點,來看一個例子:
```python def one(func): def inner(args, kwargs): print('1') return func(args, **kwargs) return inner
def two(func): def inner(args, kwargs): print('2') return func(args, **kwargs) return inner
@one @two def speak(text): print(text)
speak('Hello')
1
2
Hello
```
我們的裝飾器函數所做的唯一事情就是打印出數字 1 和數字 2。通過將裝飾器 @one
放在 @two
之前,您可以將 two()
包裝的函數包裝為 one()
。為了説明這一點,您可以切換順序以查看如何修改行為:
```python
Changing decorator order
@two @one def speak(text): print(text)
speak('Hello')
2
1
Hello
```
通過首先放置 @two
裝飾器,該函數成為最外層的函數。
總結
在本文中,我們先了解了什麼是 Python 裝飾器,它代表元編程的語法糖。 Python 裝飾器允許我們修改函數行為並允許我們以不同的方式擴展函數。
接着瞭解裝飾器是什麼以及如何使用它們。學習瞭如何允許將參數傳遞給 Python 裝飾器,學習了幾個常見的裝飾器有用的工具。最後,如何使用多個裝飾器以及裝飾器的先後順序。
參考文章:
- 一文帶你瞭解 Python 中的繼承知識點
- 如何使用 HTML 和 CSS 寫一個登錄界面
- 代碼之外:寫作是倒逼成長的最佳方式
- Redis 的快速介紹及其基本數據類型和操作
- 經久不衰的設計定律就是——不要讓我思考的設計
- 一文了解 Python 中的裝飾器
- 聊聊 Go 語言與雲原生技術
- Go Web 編程入門:驗證器
- Golang 的藝術、哲學和科學
- Django API 開發:視圖設置和路由
- Web 編程入門:什麼是Web API?
- Python 實現設計模式之工廠模式
- 好開心我進入了面試環節,那麼我該如何自我介紹?
- 鴻蒙學習筆記:利用鴻蒙JavaUI 框架的 WebView 加載在線網頁
- Go 語言入門很簡單:讀寫鎖