Python Pydantic 簡介:和 Dataclass 的區別,Alias 的簡易用法
當寫慣了 C++、Java、TypeScript 這類 Strong Typing 的語言時,想要在 Python 處理型別總會在剛開始不太習慣,因為 Python 雖然提供了 Typing,但是僅能「提示」,而不會真的拋出錯誤。
此時可以嘗試看看 Pydantic 這樣的 Library,在定義資料的時候能較為強制限制資料的格式。此篇簡單記錄 Pydantic 的基本用法,為何要用,又和原生的 Dataclass 有什麼區別。
Pydantic 的基礎功能:
- 檢查型別
- 自訂驗證
from pydantic import BaseModel
# Example 1
class User(BaseModel):
name: str
age: int
user = User(name="John", age="text") # Throw ValidationError as age is not int
# Example 2
class Product(BaseModel):
name: str
price: float = Field(gt=0)
product = Product(name="Apple", price=-10) # Throw ValidationError as price < 0
上述程式碼的兩個例子,分別建立了 User 和 Product 兩個類別。User 中定義 age 為 int 的型別,因此當我們 New Object 時,輸入 age="text" 時,Pydantic 能幫我們抓出型別上的錯誤。
再來則是第二個例子的 Field(gt=0) 則讓我們能透過 Pydnatic 自訂驗證,從而限制了 price 的數值要大於 0。
為何要用 Pydantic,和 Python 原生 Dataclass 有何差別?
前面提到了 Pydantic 能做到檢查型別、自訂驗證,而 Dataclass 則無法,我們就型別的驗證上來比較看看:
-
自動型別轉換
from 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 @dataclass class User2: name: str age: int user2 = User2(name="John", age="25") print(user2)輸出結果為
name='John' age=25 User2(name='John', age='25')當我們都將 age 定義成 int,Pydantic 會自動將我們輸入錯的
"25"這個字串轉換成整數,但是 Dataclass 並不會。 -
拋出錯誤
user1 = 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", 1, "2": "John"},
{"1", 2, "2": "Jane"}
]
其中的 Key 是不好讀的 1、2,然而代表的意思卻是 id 和 name。此時我便能透過 Pydantic 的 Alias 做處理,首先定義這些 Fields 的 Alias 為 1 和 2 來符合資料來源的 Field Keys
from pydantic import BaseModel, Field
class User(BaseModel):
id: int = Field(alias="1")
name: str = Field(alias="2")
然後讀取 JSON 檔案中的資料,透過 ** 來 Unpack 這個 Dictionary 的資訊,然後丟入我們定義的 Pydantic User Model 中
data = {"1": 1, "2": "John"} # One element from the JSON file
user = User(**data)
print(user)
最後得到 id=1 name='John',就是將 Alias 轉換成我們 Model 中 Field Name 的結果。