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

mypy — Type Hints Cheat Sheet

Contoh cepat untuk hampir setiap pola anotasi tipe yang muncul di kode Python sehari-hari.

Intisari

  • Halaman ini untuk dilihat sekilas saat menulis kode, bukan dibaca berurutan. Bookmark-lah.
  • Pola paling sering: koleksi, | None, Callable, Literal, generic.
  • TypeVar untuk fungsi yang mempertahankan tipe input di outputnya.
  • Protocol = duck typing yang bisa dicek — “apa pun yang punya method ini”.
  • reveal_type(x) membuat mypy mencetak tipe yang ia simpulkan. Alat debug tipe terbaik.

Variabel

x: int = 1
y: str                       # dideklarasikan, belum diisi
z: list[int] = []

# Biasanya tidak perlu — mypy bisa menyimpulkan sendiri
umur = 30                    # mypy tahu ini int

Anotasi variabel hanya perlu saat mypy tidak bisa menebak, misalnya list kosong.

Fungsi

def sapa(nama: str) -> str: ...
def cetak(pesan: str) -> None: ...              # tidak mengembalikan apa-apa
def gagal(pesan: str) -> NoReturn: ...          # selalu melempar exception

def konfigurasi(
    host: str,
    port: int = 8000,
    *args: str,                                  # sisa argumen posisional
    debug: bool = False,                         # setelah *: wajib bernama
    **opsi: str,                                 # sisa argumen bernama
) -> None: ...

Koleksi

a: list[str]
b: dict[str, int]
c: set[str]
d: tuple[int, str]              # persis dua elemen
e: tuple[int, ...]              # berapa pun elemen int

from collections.abc import Sequence, Iterable, Iterator, Mapping, Callable

def f(items: Sequence[str]) -> None: ...   # list ATAU tuple
def g(items: Iterable[str]) -> None: ...   # apa pun yang bisa di-for
def h(m: Mapping[str, int]) -> None: ...   # dict, read-only

Opsional dan union

nilai: str | None = None
campur: int | str | None

def cari(id: str) -> Dokumen | None: ...

Menyempitkan union

def proses(x: int | str) -> str:
    if isinstance(x, int):
        return str(x)        # di sini mypy tahu x adalah int
    return x.upper()         # di sini mypy tahu x adalah str

def pakai(d: Dokumen | None) -> str:
    if d is None:
        return ""
    return d.judul           # aman: mypy tahu d bukan None

Class

class Dokumen:
    judul: str                     # atribut tingkat class
    _cache: dict[str, str] = {}

    def __init__(self, judul: str, isi: str = "") -> None:
        self.judul = judul
        self.isi = isi

    def ringkas(self, panjang: int = 100) -> str:
        return self.isi[:panjang]

    @classmethod
    def dari_json(cls, data: dict) -> "Dokumen": ...

    @staticmethod
    def valid(teks: str) -> bool: ...

    @property
    def jumlah_kata(self) -> int:
        return len(self.isi.split())

Generator dan async

from collections.abc import Iterator, AsyncIterator, Awaitable

def baca(path: str) -> Iterator[str]:
    yield "baris"

async def ambil(url: str) -> dict: ...

async def stream(url: str) -> AsyncIterator[str]:
    yield "potongan"

def nanti() -> Awaitable[str]: ...      # sesuatu yang bisa di-await

Literal dan Final

from typing import Literal, Final

Mode = Literal["fast", "accurate"]

def jalankan(mode: Mode = "fast") -> None: ...
jalankan("cepat")     # error: Argument has incompatible type

MAX_TOKENS: Final = 4096       # mypy melarang perubahan nilai ini

TypeVar — generic

def pertama[T](items: list[T]) -> T | None:      # sintaks Python 3.12+
    return items[0] if items else None

pertama([1, 2, 3])          # mypy tahu hasilnya int | None
pertama(["a", "b"])         # mypy tahu hasilnya str | None
# Sintaks lama, masih umum ditemui
from typing import TypeVar

T = TypeVar("T")

def pertama(items: list[T]) -> T | None: ...

Protocol — duck typing yang bisa dicek

from typing import Protocol

class PunyaEmbedding(Protocol):
    def embed(self, teks: str) -> list[float]: ...

def indeks(model: PunyaEmbedding, docs: list[str]) -> None:
    for d in docs:
        model.embed(d)

Class apa pun yang punya method embed dengan tanda tangan itu akan diterima — tanpa perlu mewarisi apa pun. Ini cara mengetikkan "duck typing" yang biasa dipakai Python, dan sangat pas untuk menukar implementasi asli dengan versi palsu saat testing.

TypedDict — dict dengan bentuk tetap

from typing import TypedDict

class Pesan(TypedDict):
    role: str
    content: str

msg: Pesan = {"role": "user", "content": "halo"}   # dicek mypy

Berguna untuk struktur seperti messages di API LLM yang memang harus berupa dict.

Debugging tipe

reveal_type(hasil)      # mypy mencetak tipe yang ia simpulkan, lalu error di baris itu
note: Revealed type is "builtins.list[myapp.Dokumen]"

Jangan lupa hapus setelah selesai — reveal_type tidak ada saat runtime dan akan menyebabkan NameError kalau tertinggal.

Membungkam error

x = fungsi_aneh()  # type: ignore[no-any-return]

from typing import cast
d = cast(Dokumen, data_mentah)     # "percaya aku, ini Dokumen"

Referensi ke depan

from __future__ import annotations   # taruh di baris pertama file

class Node:
    def anak(self) -> list[Node]: ...   # boleh menyebut Node meski belum selesai didefinisikan

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