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:

python
err = ZeroDivisionError("pembagi tidak boleh nol")

print(type(err).__name__)
print(err.args)
print(err)

Output yang Dihasilkan:

text
ZeroDivisionError
('pembagi tidak boleh nol',)
pembagi tidak boleh nol

Mari kita telaah apa yang terjadi pada baris-baris kode di atas:

  1. Baris 1 (err = ZeroDivisionError("...")): interpreter Python memanggil class ZeroDivisionError seperti memanggil function biasa, membuat instance baru, lalu mengikatnya ke variabel err. Belum ada yang error pada tahap ini.
  2. Baris 3 (print(type(err).__name__)): type(err) mengembalikan class ZeroDivisionError, dan atribut __name__ berisi nama class-nya sebagai string.
  3. Baris 4 (print(err.args)): atribut args berisi tuple seluruh argumen yang diberikan saat instance dibuat — dalam hal ini satu buah string pesan.
  4. Baris 5 (print(err)): print() memanggil str(err), yang mengembalikan pesan error. Membangkitkan error baru terjadi hanya jika kita menuliskan raise 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:

python
harga_satuan = 50000
jumlah = 0

total = harga_satuan / jumlah
print("Total belanja:", total)

Output yang Dihasilkan (dicetak interpreter Python ke stderr):

text
Traceback (most recent call last):
  File "belanja.py", line 4, in <module>
    total = harga_satuan / jumlah
            ~~~~~~~~~~~~~^~~~~~~~
ZeroDivisionError: division by zero

Anatomi traceback di atas terdiri atas empat bagian:

BagianMakna
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 zeronama 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.

AspekSyntax errorException
Tahap terdeteksisebelum eksekusi (compile time)saat eksekusi (runtime)
Contohif suhu > 30 tanpa titik dua50000 / 0
Bentuk laporanpesan SyntaxError dengan penunjuk posisitraceback 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.

python
produk = {"nama": "Kopi Gayo", "stok": 12}

if "harga" in produk:
    harga = produk["harga"]
else:
    harga = 0

print("Harga:", harga)

Output yang Dihasilkan:

text
Harga: 0

Versi EAFP menyerahkan pengecekan pada mekanisme exception:

python
produk = {"nama": "Kopi Gayo", "stok": 12}

try:
    harga = produk["harga"]
except KeyError:
    harga = 0

print("Harga:", harga)

Output yang Dihasilkan:

text
Harga: 0

Kedua 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”.