DEV Community

Cover image for Pydantic 小筆記
Leon
Leon

Posted on • Originally published at editor.leonh.space

2 1

Pydantic 小筆記

故事要從 Python 的語言特性說起,因為 Python 是動態型別的,所以一個在同一個區塊(命名空間)內的變數 x,可以一下是字串,一下是整數:

x = 4
print(type(4)) # at this moment, x points to an integer

x = "Hello, world"
print(type(x)) # and at this moment, x points to a string
Enter fullscreen mode Exit fullscreen mode

這樣的特性降低了 Python 的學習曲線,但在程式專案變複雜後,對於「值」與「型態」的掌握會越來越難以駕馭。

大約在 Python 3.5 起引入了 type hints,華文叫類型提示或型態提示,它讓我們得以聲明變數的型態,也可以聲明函式回傳值的型態。

有了 type hints,IDE 或是靜態分析工具就可以幫助我們偵測型態上的錯誤,也因為它只是 hints,所以它終究無法讓 Python 變成靜態型別語言,只是一種輔助而已。

下面是最基本的 type hints 範例:

name: str = "world"

def greeting(name: str) -> str:
    return "Hello " + name

greeting(name)
Enter fullscreen mode Exit fullscreen mode

上面我們用 : str 聲明 name 為字串,以及在函式我們用 -> str 聲明 greeting() 回傳的也是字串,當然還有更複雜的用法,可以參見〈Python Type Hints 從入門到實踐〉。

以上為前情提要,下面開始談本文的主角 Pydantic

Pydantic

Pydantic 是以 type hints 為基礎,幫我們做資料型態驗證的套件,我們可以用它定義「Model」:

from pydantic import BaseModel

class EmployeeModel(BaseModel):
    name: str
    salary: int
Enter fullscreen mode Exit fullscreen mode

在這個 EmployeeModel 中,我們聲明了 name 應為字串、salary 應為整數,透過繼承自 BaseModel 的特性,pydantic 會自動幫我們驗證型態的正確性。

如果試圖建立一個實例,並提供正確的型態,那不會有任何問題(也不會有任何提示說我們好棒棒):

employee = EmployeeModel(
    name='Bar',
    salary=1000,
)
Enter fullscreen mode Exit fullscreen mode

但如果給了一個錯誤的型態,那麼 pydantic 會引發錯誤:

employee = EmployeeModel(
    name='Bar',
    salary='secret',
)
Enter fullscreen mode Exit fullscreen mode

應該要是整數的 salary,卻被塞了字串,引發 validation error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/leon/Projects/pydantic/.venv/lib/python3.10/site-packages/pydantic/main.py", line 406, in __init__
    raise validation_error
pydantic.error_wrappers.ValidationError: 1 validation error for EmployeeModel
salary
  value is not a valid integer (type=type_error.integer)
Enter fullscreen mode Exit fullscreen mode

Pydantic + FastAPI

在應用上,新興的 Python 框架 FastAPI 深度整合了 pydantic 的類型驗證特性,只要在程式碼內事先聲明類型,所有的 API 端點都自動的具備型態驗證機制,我輩開發者再也不用自己刻 e-mail、URL 等等繁瑣的驗證邏輯,香!

下面是個極簡的 FastAPI 範例:

from typing import Optional

from fastapi import FastAPI
from pydantic import BaseModel

class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None

app = FastAPI()

@app.post("/items/")
async def create_item(item: Item):
    return item
Enter fullscreen mode Exit fullscreen mode

在 Item model 中,我們定義了四個屬性,其中的 descriptiontax 的 type hints 是 Optional[str],而預設值為 NoneOptional[str] 意味著此屬性是選填的,如果建立實例時未填,則屬性值為 None

最後一個區塊定義了一個接受 POST 的 API 端點 /items/,此端點的處理函式 create_item(item: Item) 接受一個參數 item,並且該參數之型態應為前面定義的 Item model,在這樣的的定義與聲明下,前端送過來的 request body 會自動的被 pydantic 解析與驗證,並且那 FastAPI 自動產生的 OpenAPI 文件也會載明該端點的 JSON schema:

FastAPI

FastAPI

Pydantic 與 .env 環境變數管理

在開發環境(development)與生產環境(production)採用的參數可能不同,例如連接 Twitter API 的帳密、連接 MongoDB 的帳密等等,這類參數習慣上會把它與程式碼分開,另外放在 .env 檔案內,再透過像 python-dotenv 這樣的套件把 .env 讀入成為可調用的變數。Pydantic 也整合了 python-dotenv,可以幫我們做到上述工作,這部份的用法請參閱下面兩篇:

說個題外話,關於 .env 檔案,有一條常見的鐵律是不要把 .env 提交到版控系統,個人是不太認同,只要我的 Git repository 是私有的,自架的,本機的,提交到 Git repository 又何妨?版控≠開源,當我的專案是閉源的,.env 的地位就與任何一份原碼一樣隱私,不具有特殊地位,我們要守護的也不僅是 .env,而是整個專案。

結語

綜觀以上,只要在程式碼內定義好型態,就可以享有:

  • IDE 或靜態分析工具幫我們揪錯,以及程式碼的可讀性更高,大型專案更好維護
  • Pydantic 幫我們檢查打來 API 的值的型態正確與否,省去自己寫驗證邏輯的功夫,time to market 時間再省一半
  • FastAPI 自動根據我們定義的型態產生 OpenAPI 文件與規格,再也不用寫 API 規格書,再也不用回覆前端同事的私訊

參考資料

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Engage with a sea of insights in this enlightening article, highly esteemed within the encouraging DEV Community. Programmers of every skill level are invited to participate and enrich our shared knowledge.

A simple "thank you" can uplift someone's spirits. Express your appreciation in the comments section!

On DEV, sharing knowledge smooths our journey and strengthens our community bonds. Found this useful? A brief thank you to the author can mean a lot.

Okay