Program yang sudah benar secara sintaks tetap bisa gagal saat berjalan: pembagi bernilai nol, kunci dictionary yang tidak ada, atau data pengguna yang tidak sesuai harapan. Python menangani situasi seperti itu melalui mekanisme bernama exception. Pada Chapter ini kita akan mempelajari apa sebenarnya exception itu, apa yang dilakukan interpreter Python saat exception tidak ditangani, serta filosofi penanganan error yang khas Python bernama EAFP.
Exception Adalah Object #
Ketika error runtime terjadi, interpreter Python tidak sekadar “berhenti”. Interpreter Python membuat sebuah object yang mendeskripsikan error tersebut, lalu membawanya melewati kode program. Object tersebut adalah instance dari sebuah class seperti ZeroDivisionError, ValueError, atau KeyError, dan seluruh class tersebut berakar pada satu class induk bernama BaseException.
Karena exception adalah object biasa, kita bisa membuatnya sendiri tanpa langsung membangkitkan error:
err = ZeroDivisionError("pembagi tidak boleh nol")
print(type(err).__name__)
print(err.args)
print(err)Output yang Dihasilkan:
ZeroDivisionError
('pembagi tidak boleh nol',)
pembagi tidak boleh nolMari kita telaah apa yang terjadi pada baris-baris kode di atas:
- Baris 1 (
err = ZeroDivisionError("...")): interpreter Python memanggil classZeroDivisionErrorseperti memanggil function biasa, membuat instance baru, lalu mengikatnya ke variabelerr. Belum ada yang error pada tahap ini. - Baris 3 (
print(type(err).__name__)):type(err)mengembalikan classZeroDivisionError, dan atribut__name__berisi nama class-nya sebagai string. - Baris 4 (
print(err.args)): atributargsberisi tuple seluruh argumen yang diberikan saat instance dibuat — dalam hal ini satu buah string pesan. - Baris 5 (
print(err)):print()memanggilstr(err), yang mengembalikan pesan error. Membangkitkan error baru terjadi hanya jika kita menuliskanraise err.
Perilaku Default: Program Berhenti #
Ketika exception dibangkitkan dan tidak ada kode yang menangkapnya, interpreter Python menghentikan program saat itu juga, lalu mencetak laporan bernama traceback ke stderr. Simpan kode berikut sebagai belanja.py, lalu jalankan dengan python3 belanja.py:
harga_satuan = 50000
jumlah = 0
total = harga_satuan / jumlah
print("Total belanja:", total)Output yang Dihasilkan (dicetak interpreter Python ke stderr):
Traceback (most recent call last):
File "belanja.py", line 4, in <module>
total = harga_satuan / jumlah
~~~~~~~~~~~~~^~~~~~~~
ZeroDivisionError: division by zeroAnatomi traceback di atas terdiri atas empat bagian:
| Bagian | Makna |
|---|---|
Traceback (most recent call last): | header laporan; daftar panggilan dari kode terluar ke titik error |
File "belanja.py", line 4, in <module> | nama file dan nomor baris tempat error terjadi; <module> berarti kode tingkat atas |
total = harga_satuan / jumlah beserta garis ~~~^~~~ | baris sumber yang gagal; tanda tersebut menyorot operasi pembagian sebagai biang keladi |
ZeroDivisionError: division by zero | nama class exception dan pesan errornya |
Syntax Error Bukan Exception Runtime #
Syntax error dan exception adalah dua hal berbeda. Syntax error dideteksi interpreter Python pada tahap kompilasi, sebelum satu baris pun dieksekusi. Exception justru terjadi ketika kode yang valid dijalankan dan bertemu kondisi yang tidak bisa diproses.
| Aspek | Syntax error | Exception |
|---|---|---|
| Tahap terdeteksi | sebelum eksekusi (compile time) | saat eksekusi (runtime) |
| Contoh | if suhu > 30 tanpa titik dua | 50000 / 0 |
| Bentuk laporan | pesan SyntaxError dengan penunjuk posisi | traceback runtime |
Pembahasan mendalam mengenai pesan SyntaxError sudah kita lintasi pada Chapter Memahami Syntax Error. Seluruh materi pada Section ini berfokus pada exception runtime.
EAFP versus LBYL #
Komunitas Python punya dua gaya menghadapi kemungkinan error. Gaya LBYL (Look Before You Leap, “periksa dulu sebelum melompat”) memeriksa kondisi sebelum bertindak. Gaya EAFP (Easier to Ask Forgiveness than Permission, “lebih mudah meminta maaf daripada meminta izin”) langsung bertindak, lalu menangani error bila benar-benar terjadi.
produk = {"nama": "Kopi Gayo", "stok": 12}
if "harga" in produk:
harga = produk["harga"]
else:
harga = 0
print("Harga:", harga)Output yang Dihasilkan:
Harga: 0Versi EAFP menyerahkan pengecekan pada mekanisme exception:
produk = {"nama": "Kopi Gayo", "stok": 12}
try:
harga = produk["harga"]
except KeyError:
harga = 0
print("Harga:", harga)Output yang Dihasilkan:
Harga: 0Kedua versi menghasilkan output sama. Perbedaannya ada pada asumsi dasar: LBYL mengasumsikan kegagalan itu umum sehingga diperiksa lebih dulu, sedangkan EAFP mengasumsikan keberhasilan itu umum sehingga jalur utama tetap ramping. Gaya EAFP juga tahan terhadap race condition pada kode concurrency karena pemeriksaan dan tindakan menjadi satu kesatuan di sisi interpreter Python.
Cara kerja lengkap pernyataan try dan except akan kita bedah pada Chapter try dan except. Hal terpenting saat ini: exception bukan musuh, melainkan jalur komunikasi resmi interpreter Python untuk mengatakan “operasi ini gagal, dan ini alasannya”.