Python Pydantic 簡介:和 Dataclass 的區別,Alias 的簡易用法
當寫慣了 C++、Java、TypeScript 這類 Strong Typing 的語言時,想要在 Python 處理型別總會在剛開始不太習慣,因為 Python 雖然提供了 Typing,但是僅能「提示」,而不會真的拋出錯誤。
此時可以嘗試看看 Pydantic 這樣的 Library,在定義資料的時候能較為強制限制資料的格式。此篇簡單記錄 Pydantic 的基本用法,為何要用,又和原生的 Dataclass 有什麼區別。
Pydantic 的基礎功能:
- 檢查型別
- 自訂驗證
1 | from pydantic import BaseModel |
上述程式碼的兩個例子,分別建立了 User 和 Product 兩個類別。User 中定義 age 為 int 的型別,因此當我們 New Object 時,輸入 age="text"
時,Pydantic 能幫我們抓出型別上的錯誤。
再來則是第二個例子的 Field(gt=0)
則讓我們能透過 Pydnatic 自訂驗證,從而限制了 price
的數值要大於 0。
為何要用 Pydantic,和 Python 原生 Dataclass 有何差別?
前面提到了 Pydantic 能做到檢查型別、自訂驗證,而 Dataclass 則無法,我們就型別的驗證上來比較看看:
自動型別轉換
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19from pydantic import BaseModel, Field
from dataclasses import dataclass
# Pydantic
class User1(BaseModel):
name: str
age: int
user1 = User1(name="John", age="25")
print(user1)
# Dataclass
class User2:
name: str
age: int
user2 = User2(name="John", age="25")
print(user2)輸出結果為
1
2name='John' age=25
User2(name='John', age='25')當我們都將 age 定義成 int,Pydantic 會自動將我們輸入錯的
"25"
這個字串轉換成整數,但是 Dataclass 並不會。拋出錯誤
1
2user1 = User1(name="John", age="Doe") # Throw Error - age, Input should be a valid integer
user2 = User2(name="John", age="Doe") # Doesn't throw Error用 Pydantic 的 User1 會在無法轉換型別時拋出錯誤,但是 Dataclass 並不會
使用 Pydantic 定義資料 Class 時,能自動做型別轉換、驗證,以及更複雜的邏輯檢查。當出現驗證失敗後,會直接拋出錯誤。
相較之下,原生的 Dataclass 僅僅是簡單的資料容器而已,如果真的需要驗證資料型態或是邏輯檢查,還需要手動處理、拋出錯誤。
使用 Pydantic Alias 改變 Field 名稱
我在使用 Python 撰寫資料轉換的程式碼時,對於原始資料和我們定義的資料,如果有 Key 不對齊的情況,則可以使用 Pydantic 好用的功能:Alias。
例如原始資料的某個 Key 為 tw
, ny
等,但是我們想將自己定義的 Model key 寫清楚點,定義成 taiwan
, new-york
,則可以透過 Alias 達成。
首先先看一下,在 Python 中有一種符號為 **
的 Unpacking Operators(開箱運算子),後續使用 Alias 的過程中會用到。**
可以使函式收 0 到多個 Key-Value Pairs,存入 Dict 中,如 def add_animals(**kwargs)
等等。
有了 Unpacking Operators,我們便能搭配 Pydantic 的 Alias 來處理外部資料,讓一些不太好讀的欄位和符合我們制定的 Pydantic Model。
舉個例子來說,我們想讀一份儲存 User 的 JSON 文件,裡面的格式如下:
1 | [ |
其中的 Key 是不好讀的 1
、2
,然而代表的意思卻是 id
和 name
。此時我便能透過 Pydantic 的 Alias 做處理,首先定義這些 Fields 的 Alias 為 1
和 2
來符合資料來源的 Field Keys
1 | from pydantic import BaseModel, Field |
然後讀取 JSON 檔案中的資料,透過 ** 來 Unpack 這個 Dictionary 的資訊,然後丟入我們定義的 Pydantic User Model 中
1 | data = {"1": 1, "2": "John"} # One element from the JSON file |
最後得到 id=1 name='John'
,就是將 Alias 轉換成我們 Model 中 Field Name 的結果。