Pydantic: Migrating from V1 to V2 / The Introduction to Pydantic V2

The introduction to Pydantic V2

導言

  • 雖然原先的讀書分享的原主題是 Pydantic: Migrating from V1 to V2 ,但看了題目之後,我其實有些嚇一跳,因為去年初的時候,我有看過 Fred 老師油管頻道的 pydantic 課程,印象當初並不是這個標題,仔細一查果然,原先我最早看的其實是老師分享的這個介紹 Pydantic V1 的視頻 - Intro to Pydantic V1,當初的這個視頻,是 Fred 老師在 python deep dive III 的課程中,在講解 Json 序列與反序列的補充教材,當時(我分享筆記的日期是 2022/01/25)看了之後,真的是被 Pydantic 模組的強大功能所著迷與震懾,不亞於我初接觸 Numpy 的震撼,而這次的講題 Migrating from V1 to V2,感覺有些銜接的味道,由於 Pydantic v2 在 2020/08 發布,為此老師錄製了新的 Udemy 課程來專篇介紹 Pydantic V2 - Pydantic V2: Essentials,也因此有了這個主題,來作為 Pydantic V1 與這個 Udemy 新課程的銜接與暖身。因此為了不讓這次主題過度的空泛與突兀,我嘗試將兩個主題合併,會由基本 Pydantic V1 的濃縮介紹,然後再銜接到 Pydantic V2 的新功能亮點,最後再將兩者做個比較,以及簡述從 Pydantic V1 遷移到 Pydantic V2 的相關重點提示。

Pydantic 是什麼?

  • 一個針對 Python 特定類別的定義框架,用於複雜物件的類資料結構(Data Schema Construction)的建立
    • class attribute → fields
    • specialized class → model
  • 反序列化 Deserializing → 從 字典 或 json資料 載入數據到 model(class) → parse_obj()
  • 序列化 Serializing → 從 model(class) 輸出數據到 字典 或 json資料 → dict() or json()
  • 於反序列化時,可透過 validator 來進行資料驗證
  • 使用 pydantic 優點: 讓我們可以和我們的資料以一個更加 OOP 更加結構化的方式進行互動。

Pydantic V1 的重點回顧

  • Pydantic module 安裝:
    • 由於 Pydantic V2 已經發布,如果直接使用 pip install -U pydantic,預設安裝的是 Pydantic 2.0
    • 那 Pydantic 1.0 已經完全不能用了嗎? 目前還能使用,但如官方 Migration Guide 所言,你必須改用 pip install “pydantic==1.*” 來進行安裝,而 import 方式,也必須改成 from pydantic.v1 import BaseModel
    • 關於 Pydantic 1.0 的相關文件可到這裡參考。
  • 基本使用: 用於複雜物件的類資料結構(Data Schema Construction)建立,以及反序列化 Deserializing 與序列化 Serializing。
    • 例如:
class Person(BaseModel):
    first_name: str
    last_name: str
    age: int

p = Person(first_name='Isaac', last_name='Newton', age=84)    
  • 特點: 眾所周知,Python 是動態語言,其實沒有所謂的型別檢查,而 Type Hinting 也只能輔助函式的輸入輸出標示,並沒有強制性,比方說:
def multiplication(a: int, b: int) -> int:
    return a * b

print(multiplication(2, 4)) # 8
print(multiplication('a', 4)) # 'aaaa'
  • 如上面範例,即便有 type hinting,暗示 user 輸入參數必須是整數,但是你如果輸入 a = ‘2’,而字串和整數是可以相乘的,因此 print(multiplication(‘2’, 4)) 並不會報錯。
  • 但寫程式時,開發者通常是希望使用者能夠按照型別的提示來操作,以避免程式朝著非開發者設計的期望方向執行,這時就可以使用 Pydantic 來約束,如以下範例:
from pydantic.v1 import BaseModel
from pydantic.v1 import ValidationError

# 將參數變成 Data Schema 架構
class Args(BaseModel):
    a: int
    b: int

# 乘法函式
def multiplication(a: int, b: int) -> int:
    args = Args(a=a, b=b)
    return args.a * args.b

# 符合 Data Schema 型別約束,就可執行
print(multiplication(2, 4)) # 8

# 當不符合時
try:
    print(multiplication('a', 4))
except ValidationError as ex:
    print(ex) 
# 1 validation error for Args
# a value is not a valid integer
  • Note: 如果上述程式將 a 改成 ‘2’,且使用 Pydantic V2 來跑,基於 pydantic 驗證器會自動將其轉型,因此結果並不會報錯,而是跑出 8 這個結果。

  • 由於這裡只是幫大家基本複習一下 Pydantic 的基本使用,因此 Pydantic V1 模型的相關函式(如下)就不特別一一介紹了~

    • dict() - 轉換為字典
    • json() - 轉換為 JSON 字符串
    • copy() - 深拷貝模型
    • parse_obj() - 從字典創建模型實例
    • parse_raw() - 從 JSON 字符串創建模型實例
    • from_orm() - 從 ORM 模型創建 Pydantic 實例
from pydantic.v1 import BaseModel

class User(BaseModel):
    id: int # 整數
    name: str # 字符串


user = User(id=1, name='John')
user_dict = user.dict()
user_json = user.json()
new_user = User.parse_obj(user_dict)
print(user_dict) # {'id': 1, 'name': 'John'}
print(new_user)  # id=1 name='John'

Pydantic V2 簡介及新功能巡禮

  • 以下的 Pydantic V2 的介紹摘要,是從 Pydantic 官方這幾個文件所節錄的:
  • Pydantic V2 重點介紹:
    • Pydantic v2 版本於 2022 年 8 月發布,而 V2 主要的變革是使用 Rust 改寫 Pydantic-Core (Pydantic 的驗證器基底所在)。
      • V2 版本的效能比 V1(V1.9.1)在一些 pydantic-core 基準測試上提高了 50 倍
      • 在一般通用的模型驗證上,V2 比V1 足足快了 17 倍。
    • 安全性和可維護性: Pydantic V2 新架構將更加容易維護,更加安全,減少 Bug。
    • V2 直接支援 JSON 輸出,可以將 JSON 直接解析為模型或輸出類型,這既提高了性能,又避免了 嚴格性問題,這使得 Pydantic V2 模型可以與其他工具輕鬆集成。
    • V2 可以在嚴格模式和寬鬆模式下運行,其中嚴格模式不會轉換資料,而寬鬆模式則會在適當的情況下嘗試將資料強制轉換為正確的類型。
    • 驗證器功能改進: Pydantic V2 重大亮點之一
      • function before mode - 在調用內部驗證器之前調用函數
      • function after mode - 在調用內部驗證器后調用函數
      • plain mode - 沒有內部驗證器
      • wrap mode - 可直接調用 function before 與 after mode validator 或 User Custom Validator 來進行多重驗證,以下是一個 wrap mode validator 的示例:
from datetime import datetime
from pydantic import BaseModel, ValidationError, validator


class MyModel(BaseModel):
    timestamp: datetime

    @validator('timestamp', mode='wrap')
    def validate_timestamp(cls, v, handler):
        if v == 'now':
            # we don't want to bother with further validation,
            # just return the new value
            return datetime.now()
        try:
            return handler(v)
        except ValidationError:
            # validation failed, in this case we want to
            # return a default value
            return datetime(2000, 1, 1)
  • 更強大的 alias 別名功能: V2 的 Pydantic-core 可以支持別名 paths 以及簡單的字串別名(string aliases),以便在驗證數據時扁平化數據,例如:
from pydantic import BaseModel, Field


class Foo(BaseModel):
  bar: str = Field(aliases=[['baz', 2, 'qux']])


data = {
  'baz': [
      {'qux': 'a'},
      {'qux': 'b'},
      {'qux': 'c'},
      {'qux': 'd'},
  ]
}

foo = Foo(**data)
assert foo.bar == 'c'

從 Pydantic V1 遷移到 Pydantic V2 的相關重點提示

  • 以下部分我將轉換到 Fred 老師針對 Migration to Pydantic V2 這個視頻的 jupyter notebook 說明文章,以便於 線上讀書會 上的解說。 (為了方便大家閱讀,我盡可能地依照老師英文原文的精神翻譯為中文,但如果有翻譯不到位的,還請自行斟酌並多多包涵)

總結

  • 這篇筆記主要是針對老師於其 Youtube 這部主題為 Pydantic: Migrating from V1 to V2 的教學影片
    這部影片看起來是作為前一部 Intro to Pydantic V1 與 Fred 老師在 Udemy 線上課程平台新開的 Pydantic V2: Essentials 課程的銜接

  • 我推測這是因為 老師在 Udemy 線上課程平台新開的 Pydantic V2: Essentials 課程中,不再提及 V1 與 V2 之間的差異 (為此我幾乎先看完這課程第一章的課程才推測出原因),而是 把這課程作為初接觸 Pydantic 的入門(直接入門 V2)

  • 然而這樣的做法會讓 已經接觸過 Pydantic V1 的學生,會有些難適應 Pydantic V2 (V2 改掉蠻多 V1 的語法),或許可能是考慮到這樣的可能性,Fred 老師才錄製了這個 Pydantic: Migrating from V1 to V2 的 Youtube 影片,以幫助這些已經接觸過 Pydantic V1 的學生,讓他們能知悉 Pydantic V1 與 V2 的差異性,幫助大家能更快過渡到 Pydantic V2,以及提出後續該如何進階學習 Pydantic V2 的建議。

  • Pydantic 這個模組真的是非常強大,非常推薦大家學習,也希望這篇筆記在大家學習 Pydantic 的過程中能幫助到大家。

2個讚