Di Python, function adalah nilai biasa: function bisa disimpan ke variabel, dikirim sebagai argument, dan dikembalikan oleh function lain — kita telah memanfaatkan hal ini saat belajar higher-order function pada Section Fungsi. Konsekuensinya, kita butuh cara menganotasi “sesuatu yang bisa dipanggil” beserta bentuk parameternya. Sementara itu, anotasi yang berguna sering tumbuh panjang dan berulang — dict[str, list[tuple[int, str]]] tiga kali dalam satu file mengundang salah ketik. Chapter ini menyelesaikan dua masalah tersebut dengan Callable dan type aliases.
Mengetik Function sebagai Nilai #
Tipe Callable hidup di module collections.abc (bentuk typing.Callable juga tersedia). Anotasinya berbentuk daftar parameter di dalam kurung siku, diikuti tipe nilai balik:
from collections.abc import Callable
Operasi = Callable[[int, int], int]
def hitung(a: int, b: int, operasi: Operasi) -> int:
return operasi(a, b)
print(hitung(10, 3, lambda a, b: a + b))
print(hitung(10, 3, lambda a, b: a * b))Output yang Dihasilkan:
13
30Mari kita telaah baris-barisnya:
- Baris 3 (
Operasi = Callable[[int, int], int]): aliasOperasidibaca “callable yang menerima duaintlalu mengembalikanint”. List di dalam kurung siku pertama adalah daftar tipe parameter; elemen setelah koma terakhir adalah tipe nilai balik. - Baris 5 (
operasi: Operasi): parameter ketigahitungmenerima function apa pun yang cocok dengan bentuk tersebut —lambda, named function, atau method. - Baris 6 (
operasi(a, b)): karena checker tahuoperasimenerima duaintdan mengembalikanint, pemanggilan ini diperiksa penuh, bukan diperlakukan sebagaiAny.
Anotasi Callable tanpa detail — Callable[..., int] — juga sah; ellipsis berarti “parameter apa pun”. Gunakan hanya untuk function yang benar-benar menerima bentuk bebas, karena ellipsis mematikan pemeriksaan argument.
Checker menegakkan kontrak ini sekuat kontrak tipe lainnya. Simpan sebagai tugas.py:
from collections.abc import Callable
def jalankan(tugas: Callable[[int], int]) -> int:
return tugas(21)
print(jalankan("bukan callable"))python3 -m mypy tugas.pyOutput yang Dihasilkan:
tugas.py:6: error: Argument 1 to "jalankan" has incompatible type "str"; expected "Callable[[int], int]" [arg-type]
Found 1 error in 1 file (checked 1 source file)Type Alias: Nama Baru untuk Tipe Panjang #
Type alias paling sederhana hanyalah penugasan biasa — sebuah nama baru untuk ekspresi tipe yang sudah ada:
HargaMenu = dict[str, int]
menu: HargaMenu = {"kopi": 12000, "teh": 8000}
print(menu["kopi"] + menu["teh"])Output yang Dihasilkan:
20000Di mata checker — dan di runtime — HargaMenu adalah dict[str, int]; alias bukan tipe baru, hanya nama lain. Karena dibuat dengan penugasan biasa, alias semacam ini dievaluasi langsung saat baris penugasan berjalan (eager). Konsekuensi kecilnya: jika alias merujuk class yang baru didefinisikan di baris bawah, kita harus menuliskan namanya sebagai string.
Statement type pada Python 3.12 #
Python 3.12 memperkenalkan cara deklaratif untuk alias: statement type. Bentuknya menyerupai penugasan, tetapi checker memperlakukannya sebagai definisi tipe yang dievaluasi dengan malas (lazy):
type Pelanggan = dict[str, str | int]
pelanggan: Pelanggan = {"nama": "Budi", "umur": 25}
print(pelanggan["nama"])Output yang Dihasilkan:
BudiKata kunci type di awal baris adalah pembeda penting: type Pelanggan = ... membuat definisi tipe, sedangkan Pelanggan = ... (tanpa type) membuat objek dictionary biasa di runtime — dua hal yang jauh berbeda maknanya bagi checker.
Keunggulan utama evaluasi malas: alias bisa merujuk dirinya sendiri untuk struktur rekursif, tanpa string dan tanpa from __future__ import annotations. Contoh klasiknya adalah bentuk data JSON:
type JSON = int | float | str | bool | None | list[JSON] | dict[str, JSON]Definisi JSON di atas sah karena seluruh sisi kanan tidak dievaluasi sampai checker membutuhkannya. Dengan alias penugasan lama, list[JSON] di baris yang sama dengan definisinya justru galat NameError.
Satu peringatan penamaan: meskipun alias bisa dinamai bebas, konvensi PEP 8 menyarankan huruf kapital di tiap kata (HargaMenu, Operasi, JSON) agar pembaca langsung mengenali sebuah nama sebagai tipe, bukan variabel biasa.