Type hint: pengantar

Anotasi type hint pada fungsi, manfaatnya, dan alat yang membaca anotasi tersebut.

Daftar isi

Type hint adalah anotasi tipe yang ditulis pada parameter dan nilai kembalian fungsi, dengan bentuk nama: tipe dan -> tipe. Python tidak memeriksanya pada saat program berjalan, melainkan menyimpannya sebagai data yang dapat dibaca alat bantu. Topik ini membahas penulisan anotasi, tipe yang sering dipakai, cara membacanya, serta peran pemeriksa statis seperti mypy.

Anotasi ditulis setelah nama parameter, dipisahkan tanda titik dua, sedangkan tipe nilai kembalian ditulis setelah daftar parameter dengan tanda panah ->. Fungsi yang dianotasi tetap berperilaku seperti biasa, yaitu badannya dijalankan tanpa pemeriksaan tipe tambahan.

python Contoh: fungsi dengan anotasi tipe
def luas_persegi(sisi: float) -> float:
    return sisi * sisi

print(luas_persegi(4.5))
text Keluaran
20.25

Anotasi menyatakan maksud, yaitu sisi berupa angka desimal dan hasilnya juga demikian. Pembaca fungsi memperoleh informasi itu tanpa membaca badannya, dan editor dapat menampilkan saran lengkap ketika fungsi ini dipanggil. Anotasi pada parameter dengan nilai default ditulis sebelum defaultnya, misalnya ulang: int = 1.

Manfaatnya paling terasa pada editor. Saran lengkap yang muncul saat mengetik, peringatan argumen yang tertukar, dan pergantian nama parameter menjadi lebih akurat karena editor mengetahui tipe yang diharapkan. Anotasi juga berperan sebagai dokumentasi yang tidak ikut usang, karena pemeriksa statis melaporkan setiap ketidakcocokan antara anotasi dan badan fungsi.

Membaca anotasi saat program berjalan#

Meskipun tidak diperiksa, anotasi tidak hilang begitu saja. Python menyimpannya pada atribut __annotations__ berbentuk dictionary, sehingga kerangka kerja dan alat bantu dapat membacanya pada saat program berjalan.

python Contoh: membaca __annotations__
def sapa(nama: str, ulang: int = 1) -> str:
    return " ".join([nama] * ulang)

print(sapa("Halo", 2))
print(sapa.__annotations__)
text Keluaran
Halo Halo
{'nama': <class 'str'>, 'ulang': <class 'int'>, 'return': <class 'str'>}

Dictionary tersebut memuat setiap parameter beserta tipenya, ditambah entri return untuk nilai kembalian. Perilaku inilah yang dipakai kerangka kerja seperti FastAPI untuk membangun validasi secara otomatis dari anotasi fungsi, sehingga anotasi yang sama melayani pembaca, editor, dan pustaka sekaligus.

Tipe yang sering dipakai#

Tipe dasar ditulis langsung, seperti int, float, str, dan bool. Untuk koleksi, Python 3.9 ke atas menerima bentuk langsung seperti list[float] dan dict[str, int], sedangkan kemungkinan tidak adanya nilai ditulis dengan tanda |, misalnya str | None.

python Contoh: anotasi pada koleksi
def rata_rata(nilai: list[float]) -> float:
    return sum(nilai) / len(nilai)

def jumlah_siswa(kelas: dict[str, int]) -> int:
    return sum(kelas.values())

print(rata_rata([80, 90, 85]))
print(jumlah_siswa({"A": 30, "B": 25}))
text Keluaran
85.0
55

Parameter nilai dianotasikan sebagai list berisi angka desimal, dan kelas sebagai dictionary dengan kunci string serta nilai bilangan bulat. Bentuk list[float] membuat isi koleksi ikut terdokumentasi, bukan hanya jenis wadahnya, sehingga aturan data yang diterima terbaca dari tanda tangan fungsi.

python Contoh: nilai kembalian yang dapat berupa None
def cari_siswa(nama: str, daftar: list[str]) -> str | None:
    if nama in daftar:
        return nama
    return None

print(cari_siswa("Budi", ["Ali", "Budi"]))
print(cari_siswa("Dewi", ["Ali", "Budi"]))
text Keluaran
Budi
None

Tipe str | None menyatakan dua kemungkinan, yaitu nama yang ditemukan atau None apabila tidak ada. Konvensi ini menjadikan nilai kembalian yang dapat gagal terbaca dari tandanya, tanpa perlu membaca badan fungsi atau menjalankannya. Tanda | diperkenalkan pada Python 3.10 sebagai bentuk ringkas, sedangkan bentuk lama Optional[str] dari modul typing masih banyak ditemui pada kode yang lebih tua.

Pemeriksa statis dan batasan#

Python tidak menolak argumen yang bertipe salah. Anotasi hanyalah petunjuk, sehingga pemanggilan dengan tipe yang tidak sesuai tetap berjalan sepanjang operasinya memungkinkan. Contoh berikut memanggil fungsi yang dianotasi int dengan argumen string.

python Contoh: Python tidak memeriksa anotasi saat berjalan
def kali(a: int, b: int) -> int:
    return a * b

print(kali("ha", 3))
text Keluaran
hahaha

Perkalian string dengan bilangan bulat sah pada Python, sehingga kali("ha", 3) menghasilkan hahaha tanpa error apa pun, meskipun anotasinya menyatakan int. Inilah alasan pemeriksaan tipe dikerjakan alat terpisah yang berjalan sebelum program dieksekusi, dan mypy merupakan pemeriksa statis yang paling umum dipakai.

Setelah dipasang dengan pip, mypy membaca anotasi lalu melaporkan ketidakcocokan tanpa menjalankan program. Untuk berkas kali.py berikut, mypy melaporkan bahwa argumen pertama berupa str padahal dianotasikan int, lengkap dengan barisnya.

python
# tidak-dijalankan
# isi berkas kali.py yang diperiksa mypy di luar sandbox
def kali(a: int, b: int) -> int:
    return a * b

kali("dua", 3)

Pemeriksaan semacam ini menangkap kekeliruan pada baris pemanggil, yang tidak terlihat sama sekali oleh Python. Manfaatnya paling terasa pada proyek yang berkembang bersama tim, karena kesalahan tipe tertangkap sebelum program dijalankan. Anotasi pada variabel lokal biasanya tidak diperlukan karena tipenya sudah terbaca dari penugasannya, sedangkan batas antar bagian program, yaitu parameter dan nilai kembalian fungsi, paling bernilai untuk dianotasi. Untuk kelas dan struktur yang lebih kompleks, modul typing menyediakan bentuk tambahan seperti Optional, Union, dan Protocol.

bash
# tidak-dijalankan
# memasang mypy, lalu memeriksa berkas kali.py
pip install mypy
mypy kali.py

Kesalahan umum#

Kesalahan pertama adalah mengira anotasi berubah menjadi pemeriksaan otomatis saat program dijalankan. Python memperlakukan anotasi sebagai data saja, sehingga argumen bertipe salah tetap diterima sepanjang operasinya sah, sebagaimana ditunjukkan oleh kali("ha", 3) pada bagian sebelumnya. Validasi yang benar-benar menolak data tetap harus ditulis secara eksplisit di dalam badan fungsi.

Kesalahan kedua adalah menulis anotasi yang tidak benar, misalnya menandai hasil operator / sebagai int padahal operator itu selalu menghasilkan float. Anotasi yang menyesatkan lebih buruk daripada tanpa anotasi, karena pemeriksa memercayainya dan melaporkan tempat yang sebenarnya aman sebagai tempat yang salah.

Kesalahan ketiga adalah menandai hampir semua tipe sebagai Any, yang berarti menerima apa saja. Nilai petunjuknya hilang, sehingga pemeriksa tidak dapat menolak apa pun di sekitarnya. Any dipakai hanya pada bagian yang tipenya memang tidak dapat ditentukan, misalnya antarmuka dengan data yang bentuknya bebas, sedangkan bagian lainnya dianotasi sepesifik mungkin.

Ringkasan#

  • Anotasi nama: tipe dan -> tipe mendokumentasikan tipe parameter dan nilai kembalian tanpa mengubah perilaku fungsi.
  • Python menyimpan anotasi di atribut __annotations__, sehingga kerangka kerja dan alat bantu dapat membacanya saat program berjalan.
  • Bentuk list[float], dict[str, int], dan str | None merinci isi koleksi serta kemungkinan ketiadaan nilai.
  • Anotasi tidak diperiksa Python saat eksekusi, sehingga pemeriksaan statis dikerjakan alat terpisah seperti mypy.

Referensi#