Type Hints — Python

Type Hints di Python Type hints (annotation) memberi tahu tipe parameter dan return value tanpa mengubah perilaku runtime Python. Ditambahkan resmi di PEP…

Type hint adalah catatan di kode yang menyebut tipe sebuah parameter, nilai return, atau variabel, misalnya "total ini int". Bayangin label di toples dapur Warung Kopi Pak Darto: "GULA", "GARAM". Labelnya memberi tahu isi yang seharusnya, tapi toplesnya gak menolak kalau garam dimasukkan ke toples gula. Yang menangkap kesalahan itu pemeriksa yang membaca labelnya sebelum warung buka. Di Python, pemeriksa itu tool seperti mypy, dan Python sendiri tetap menjalankan kodenya apa adanya.

🧪 Tebakan cepat: def total_harga(harga: int, jumlah: int) -> int: badannya return harga * jumlah. Program memanggil print(total_harga("15000", 3)), dengan "15000" sebagai string. Python berhenti dengan error, atau mencetak sesuatu? Tebak dulu, jawabannya ada di bagian "Hint gak dipaksa saat program jalan".

Menulis type hint

def diskon(total: int) -> int:
    if total >= 100000:
        return 15
    elif total >= 50000:
        return 10
    elif total >= 25000:
        return 5
    else:
        return 0

hari_ini: int = 89000
print(diskon(hari_ini))   # 10

Hint gak dipaksa saat program jalan

def total_harga(harga: int, jumlah: int) -> int:
    return harga * jumlah

print(total_harga("15000", 3))
$ python3 warung.py
150001500015000

Python membaca hint-nya dan menyimpannya (total_harga.__annotations__ berisi {'harga': <class 'int'>, 'jumlah': <class 'int'>, 'return': <class 'int'>}), tapi gak memeriksanya. String dikali 3 artinya diulang tiga kali, jadi hasilnya teks "15000" tiga kali berderet, bukan 45000. Programnya jalan tanpa error, dan angkanya diam-diam salah. Itu jawaban tebakannya.

Ganti "15000" dengan None, dan baru ada error. Itu pun datang dari operasi * di baris 2, bukan dari hint-nya:

Traceback (most recent call last):
  File "/home/darto/warung.py", line 4, in <module>
    print(total_harga(None, 3))
          ~~~~~~~~~~~^^^^^^^^^
  File "/home/darto/warung.py", line 2, in total_harga
    return harga * jumlah
           ~~~~~~^~~~~~~~
TypeError: unsupported operand type(s) for *: 'NoneType' and 'int'

mypy: pemeriksa yang membaca hint

mypy membaca kodemu tanpa menjalankannya, lalu membandingkan tiap pemakaian dengan hint-nya. Pasang sekali dengan pip install mypy, lalu:

$ mypy warung.py
warung.py:4: error: Argument 1 to "total_harga" has incompatible type "str"; expected "int"  [arg-type]
Found 1 error in 1 file (checked 1 source file)

Tipe untuk list dan dict

def laris(penjualan: dict[str, int], minimal: int = 3) -> list[str]:
    return [menu for menu, jumlah in penjualan.items() if jumlah >= minimal]

penjualan = {"kopi susu": 3, "teh manis": 4, "roti bakar": 2}
print(laris(penjualan))      # ['kopi susu', 'teh manis']
print(laris(penjualan, 2))   # ['kopi susu', 'teh manis', 'roti bakar']

Latihan pelajaran ini memakai pola yang sama untuk nilai ujian: filter_lulus(nilai: list[int], batas: int = 70) -> list[int].

Urutannya selalu begini: def nama(param: tipe) -> tipe_return:. Tanda -> dan tipe return-nya ada sebelum titik dua. list<int> gaya Java atau TypeScript, dan def rata(n: list[int]): -> float yang menaruh -> sesudah titik dua, dua-duanya ditolak dengan SyntaxError: invalid syntax.

Boleh kosong: X | None

menu.get(nama) memberi None kalau menunya gak ada. Hint-nya int | None, artinya "int, atau None":

def cari_harga(menu: dict[str, int], nama: str) -> int | None:
    return menu.get(nama)

menu = {"kopi susu": 15000, "teh manis": 5000}
harga = cari_harga(menu, "es teh")
print(harga + 1000)

Python baru gagal saat jalan, TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'. mypy sudah menangkapnya sebelum itu:

$ mypy warung.py
warung.py:6: error: Unsupported operand types for + ("None" and "int")  [operator]
warung.py:6: note: Left operand is of type "int | None"
Found 1 error in 1 file (checked 1 source file)

Perbaikannya, cek dulu dengan if harga is None: (is None mengecek apakah nilainya None), dan hitung di else. mypy pun menjawab Success.

⚠️ Jebakan yang sering ketemu

TL;DR: Type hint menulis tipe yang diharapkan: param: tipe di parameter, -> tipe sebelum titik dua di akhir def, dan nama: tipe = nilai di variabel. Python gak memaksa hint saat jalan: total_harga("15000", 3) dengan hint int tetap jalan dan mencetak 150001500015000. Tool seperti mypy membaca hint tanpa menjalankan kode dan melaporkan incompatible type sebelum program jalan; fungsi tanpa hint gak diperiksa. Koleksi ditulis dengan kurung siku tanpa import: list[int], dict[str, int], tuple[str, int], set[str]. Nilai yang boleh kosong: int | None, sama dengan Optional[int]. Bentuknya selalu def rata(n: list[int]) -> float:, bukan list<int>.

Yang akan kamu pelajari