Anotasi nama: str menggambarkan satu nilai, tetapi data nyata hampir selalu bergerak dalam koleksi: daftar harga, kamus stok, himpunan tag. Anotasi list saja tidak menjawab pertanyaan terpenting — berisi apa list tersebut? Satu tipe koleksi bisa menampung isi apa pun, jadi tipe koleksi perlu parameter: satu tipe lagi yang mendeskripsikan setiap elemennya. Kita mulai dari empat generic type bawaan yang menutup 90% kebutuhan sehari-hari.

Empat Generik Bawaan yang Paling Sering Dipakai #

Sejak Python 3.9, tipe bawaan bisa langsung diparameterisasi dengan tanda kurung siku:

AnotasiArtiContoh isi sah
list[int]list yang setiap elemennya int[5000, 7500]
dict[str, int]dictionary key str, value int{"kopi": 12}
tuple[int, int]tuple tetap dua elemen int(-6, 121)
set[str]set yang setiap elemennya str{"promo", "baru"}

Mari kita lihat keempatnya bekerja dalam satu program:

python
harga: list[int] = [5000, 7500, 12000]
stok: dict[str, int] = {"kopi": 12, "teh": 8}
koordinat: tuple[int, int] = (-6, 121)
tags: set[str] = {"promo", "baru"}

print(harga)
print(stok)
print(koordinat)
print(sorted(tags))

Output yang Dihasilkan:

text
[5000, 7500, 12000]
{'kopi': 12, 'teh': 8}
(-6, 121)
['baru', 'promo']

Mari kita telaah baris-barisnya:

  1. Baris 1 (harga: list[int] = ...): variabel harga dianotasi sebagai list of integer; checker kini akan menolak bila kita menambahkan string ke dalamnya.
  2. Baris 2 (stok: dict[str, int] = ...): dua parameter generik terbaca berurutan — key bertipe str, value bertipe int.
  3. Baris 3 (koordinat: tuple[int, int]): tuple dengan jumlah elemen tetap; setiap posisi mendapatkan tipe masing-masing, dan jumlahnya dihitung.
  4. Baris 4 (tags: set[str] = ...): himpunan string; kita mencetak sorted(tags) karena urutan iterasi set bisa berbeda-beda, sorted() membuat keluaran selalu sama.

tuple yang Panjangnya Bebas #

tuple[int, int] mengunci jumlah elemen — cocok untuk koordinat atau pasangan tetap. Untuk baris data sepanjang apa pun, gunakan ellipsis ...:

python
def rata_rata(nilai: tuple[int, ...]) -> float:
    return sum(nilai) / len(nilai)

print(rata_rata((80, 90, 100)))

Output yang Dihasilkan:

text
90.0

Anotasi tuple[int, ...] dibaca “tuple berisi integer, sepanjang apa pun, termasuk kosong”. Bedakan dua bentuk ini dengan cermat: tuple[int, int] berarti tepat dua elemen, sedangkan tuple[int, ...] berarti banyak elemen bertipe sama.

Generik Bersarang dan Signature Function #

Parameter generik bisa diisi tipe generik lain, dan di sinilah anotasi mulai menjelaskan struktur data secara utuh:

python
def total_per_kategori(kategori: dict[str, list[int]]) -> dict[str, int]:
    return {nama: sum(harga) for nama, harga in kategori.items()}

data = {"makanan": [5000, 7500], "minuman": [3000, 4000]}
print(total_per_kategori(data))

Output yang Dihasilkan:

text
{'makanan': 12500, 'minuman': 7000}

Signature total_per_kategori kini membaca dirinya sendiri: terima dictionary yang key-nya nama kategori dan value-nya list of harga, lalu kembalikan dictionary nama ke total. Anotasi bersarang dibaca dari dalam ke luar — list[int] adalah tipe value dictionary, dan keseluruhan dict[str, list[int]] adalah tipe parameter. Pembaca signature tidak perlu menebak bentuk data lagi.

Checker Membaca Isi Koleksi #

Anotasi generik baru terasa manfaatnya saat checker menolak kesalahan. Simpan sebagai harga.py:

python
harga: list[int] = [5000, 7500]
harga.append("kopi")

Baris kedua sah-sah saja menurut runtime — list Python menerima tipe apa pun. Namun mypy memahami kontrak list[int]:

bash
python3 -m mypy harga.py

Output yang Dihasilkan:

text
harga.py:2: error: Argument 1 to "append" of "list" has incompatible type "str"; expected "int"  [arg-type]
Found 1 error in 1 file (checked 1 source file)

Checker tahu bahwa method append milik list[int] hanya menerima int — pengetahuan itu diturunkan dari parameter generik yang kita tulis. Tanpa parameter tersebut, anotasi list polos akan membuat checker pasrah dan kesalahan lolos.

Sintaks Lama: typing.List #

Sebelum Python 3.9, tipe bawaan belum bisa diparameterisasi, jadi kita wajib mengimpor bentuk kapital dari module typing:

python
from typing import Dict, List

harga_lama: List[int] = [5000]
stok_lama: Dict[str, int] = {"kopi": 12}

Dua gaya tersebut setara di mata checker, dan bentuk kapital masih ditemui di kode lama maupun dokumentasi lama. Untuk kode baru yang berjalan di Python 3.9 ke atas, PEP 585 dan panduan resmi merekomendasikan bentuk huruf kecil: list[int], bukan List[int] — lebih pendek, tanpa import, dan konsisten dengan syntax pembuatan koleksi itu sendiri.