← Semua pembelajaran / Python untuk AI Engineer
Fase 2 · Type Hints & Pydantic

Pydantic — Getting Started

Pengantar Pydantic: memvalidasi dan mem-parsing data dari luar memakai type hint biasa.

Sumber asli pydantic.dev Resmi Rangkuman ~6 menit baca

Intisari

  • Pydantic mengubah type hint jadi validasi runtime. Type hint memberi skema; Pydantic menegakkannya.
  • Alur intinya: data mentah → Model.model_validate() → objek Python yang sudah pasti benar.
  • Kesalahan validasi terkumpul jadi satu ValidationError yang menyebut lokasi tiap masalah.
  • Pastikan yang kamu baca v2. Semua method v2 diawali model_; v1 memakai nama lain.
  • Pydantic dipakai FastAPI, SDK LLM, dan konfigurasi aplikasi — investasi belajar di sini terbayar berkali-kali.

Masalah yang diselesaikan Pydantic

Data dari luar tidak bisa dipercaya. Respons API bisa kehilangan field, angka bisa datang sebagai string, dan field wajib bisa berisi null. Tanpa validasi, kesalahan itu menyebar jauh ke dalam kodemu sebelum akhirnya meledak di tempat yang tidak berhubungan.

# Tanpa Pydantic — meledak jauh dari sumber masalahnya
data = response.json()
kirim_email(data["user"]["email"])     # KeyError? None? angka?
# Dengan Pydantic — gagal di batas sistem, dengan pesan yang jelas
from pydantic import BaseModel

class Pengguna(BaseModel):
    nama: str
    email: str
    umur: int

u = Pengguna.model_validate(response.json())   # ← gagal di SINI kalau data buruk
kirim_email(u.email)                            # dijamin str

Install & model pertama

uv add pydantic
from pydantic import BaseModel

class Tiket(BaseModel):
    judul: str
    prioritas: str = "medium"        # nilai default = field opsional
    tag: list[str] = []
    ditutup: bool = False

t = Tiket(judul="Server down")
print(t)
# judul='Server down' prioritas='medium' tag=[] ditutup=False

Perhatikan tag: list[str] = []. Di dataclass ini error; di Pydantic ini aman — Pydantic membuat salinan baru untuk tiap instance. Ini salah satu perbedaan perilaku yang membedakan keduanya.

Empat cara membuat model

Tiket(judul="A")                        # dari argumen bernama
Tiket.model_validate({"judul": "A"})    # dari dict — inilah yang biasa dipakai
Tiket.model_validate_json('{"judul": "A"}')   # langsung dari string JSON
Tiket(**data_dict)                      # unpacking (kurang aman, tidak validasi bentuk)

Membaca error validasi

from pydantic import ValidationError

try:
    Tiket.model_validate({"prioritas": 123})
except ValidationError as e:
    print(e)
2 validation errors for Tiket
judul
  Field required [type=missing, input_value={'prioritas': 123}]
prioritas
  Input should be a valid string [type=string_type, input_value=123]

Perhatikan: kedua masalah dilaporkan sekaligus. Pydantic tidak berhenti di kesalahan pertama. Untuk API, ini artinya klien mendapat daftar lengkap apa saja yang salah dalam satu respons — bukan satu per satu di tiap percobaan.

e.errors()      # daftar dict — cocok untuk dijadikan respons API JSON
e.json()        # langsung jadi string JSON

Serialisasi — arah sebaliknya

t.model_dump()                       # {'judul': 'A', 'prioritas': 'medium', ...}
t.model_dump(exclude_none=True)      # buang field yang None
t.model_dump(exclude={"tag"})        # buang field tertentu
t.model_dump_json(indent=2)          # langsung jadi string JSON

Konversi otomatis (coercion)

class Konfig(BaseModel):
    port: int
    debug: bool

Konfig(port="8000", debug="true")    # port=8000 (int), debug=True (bool)

Ini disengaja dan sangat berguna — environment variable dan query string selalu berupa string. Tapi konversinya tidak sembarangan: Konfig(port="bukan angka") tetap gagal. Kalau kamu ingin konversi dimatikan sepenuhnya, pakai model_config = ConfigDict(strict=True).

Model bersarang

class Alamat(BaseModel):
    jalan: str
    kota: str

class Pengguna(BaseModel):
    nama: str
    alamat: Alamat                 # divalidasi secara rekursif
    riwayat: list[Alamat] = []

u = Pengguna.model_validate({
    "nama": "Budi",
    "alamat": {"jalan": "Jl. Merdeka 1", "kota": "Bandung"},
})
u.alamat.kota      # 'Bandung' — sudah jadi objek Alamat, bukan dict

Peringatan v1 vs v2

Banyak tutorial dan jawaban StackOverflow masih memakai API v1. Cara cepat mengenalinya:

v1 (jangan pakai)v2 (yang benar)
.dict().model_dump()
.json().model_dump_json()
.parse_obj().model_validate()
.parse_raw().model_validate_json()
.schema().model_json_schema()
@validator@field_validator
@root_validator@model_validator
class Config:model_config = ConfigDict(...)

Aturan cepat: kalau method-nya diawali model_, itu v2.

Kenapa ini fase yang tidak boleh dilewati

Pydantic muncul di setiap fase sesudah ini:

Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.