Error Handling¶
Error handling memungkinkan program menangani kesalahan dengan anggun tanpa crash. Python menggunakan mekanisme try-except untuk menangani exception.
Jenis Error¶
Syntax Error¶
Kesalahan penulisan kode yang terdeteksi saat parsing:
# SyntaxError - tanda kurung tidak lengkap
# print("Halo"
# SyntaxError - indentasi salah
# if True:
# print("test")
Exception¶
Kesalahan yang terjadi saat runtime:
# ZeroDivisionError
# hasil = 10 / 0
# TypeError
# hasil = "2" + 2
# NameError
# print(variabel_tidak_ada)
# IndexError
# list = [1, 2, 3]
# print(list[10])
# KeyError
# dict = {"a": 1}
# print(dict["b"])
# FileNotFoundError
# f = open("tidak_ada.txt")
Try-Except¶
Menangkap dan menangani exception:
try:
hasil = 10 / 0
except ZeroDivisionError:
print("Error: Tidak bisa membagi dengan nol!")
print("Program berlanjut...")
Menangkap Multiple Exceptions¶
try:
angka = int(input("Masukkan angka: "))
hasil = 10 / angka
except ValueError:
print("Error: Input bukan angka!")
except ZeroDivisionError:
print("Error: Tidak bisa membagi dengan nol!")
Menangkap Exception dalam Satu Blok¶
try:
# kode yang mungkin error
pass
except (ValueError, TypeError) as e:
print(f"Error: {e}")
Menangkap Semua Exception¶
try:
# kode berbahaya
pass
except Exception as e:
print(f"Terjadi error: {e}")
Peringatan
Menangkap semua exception sebaiknya dihindari karena bisa menyembunyikan bug yang tidak terduga. Gunakan hanya jika benar-benar diperlukan.
Else dan Finally¶
else¶
Dieksekusi jika tidak ada exception:
try:
angka = int("42")
except ValueError:
print("Bukan angka!")
else:
print(f"Berhasil: {angka}")
finally¶
Selalu dieksekusi, ada exception atau tidak:
try:
f = open("data.txt", "r")
data = f.read()
except FileNotFoundError:
print("File tidak ditemukan!")
finally:
print("Blok finally selalu dieksekusi")
# Pastikan file ditutup
Contoh Lengkap¶
def baca_file(nama_file):
try:
f = open(nama_file, "r")
data = f.read()
except FileNotFoundError:
print(f"File {nama_file} tidak ditemukan!")
return None
except PermissionError:
print("Tidak ada izin untuk membaca file!")
return None
else:
print("File berhasil dibaca!")
return data
finally:
print("Operasi selesai")
try:
f.close()
except:
pass
Raise Exception¶
Membangkitkan exception secara manual:
def set_umur(umur):
if umur < 0:
raise ValueError("Umur tidak boleh negatif!")
if umur > 150:
raise ValueError("Umur tidak realistis!")
return umur
try:
set_umur(-5)
except ValueError as e:
print(f"Error: {e}")
Custom Exception¶
Membuat exception sendiri:
class NilaiTidakValidError(Exception):
"""Exception untuk nilai yang tidak valid."""
pass
class NilaiTerlaluTinggiError(NilaiTidakValidError):
"""Exception untuk nilai lebih dari 100."""
pass
class NilaiNegatifError(NilaiTidakValidError):
"""Exception untuk nilai negatif."""
pass
def set_nilai(nilai):
if nilai < 0:
raise NilaiNegatifError(f"Nilai {nilai} tidak boleh negatif!")
if nilai > 100:
raise NilaiTerlaluTinggiError(f"Nilai {nilai} melebihi 100!")
return nilai
try:
set_nilai(150)
except NilaiTerlaluTinggiError as e:
print(f"Error nilai terlalu tinggi: {e}")
except NilaiNegatifError as e:
print(f"Error nilai negatif: {e}")
except NilaiTidakValidError as e:
print(f"Error nilai tidak valid: {e}")
Assert¶
Memeriksa kondisi dan raise AssertionError jika False:
def hitung_rata_rata(nilai):
assert len(nilai) > 0, "List tidak boleh kosong!"
return sum(nilai) / len(nilai)
try:
rata = hitung_rata_rata([])
except AssertionError as e:
print(f"Assertion gagal: {e}")
Catatan
Assert sebaiknya digunakan untuk debugging, bukan untuk menangani input user. Assert bisa dinonaktifkan dengan flag -O.
Exception Chaining¶
Menghubungkan exception dengan exception lain:
def proses_data(filename):
try:
f = open(filename)
data = f.read()
except FileNotFoundError as e:
raise ValueError(f"Tidak bisa memproses: file tidak ada") from e
try:
proses_data("tidak_ada.txt")
except ValueError as e:
print(f"Error: {e}")
print(f"Penyebab: {e.__cause__}")
Context Manager untuk Error Handling¶
Menggunakan contextlib untuk penanganan yang lebih bersih:
from contextlib import contextmanager
@contextmanager
def buka_file(nama):
f = None
try:
f = open(nama, "r")
yield f
except FileNotFoundError:
print(f"File {nama} tidak ditemukan!")
yield None
finally:
if f:
f.close()
with buka_file("data.txt") as f:
if f:
print(f.read())
Logging Error¶
Menggunakan modul logging untuk mencatat error:
import logging
# Konfigurasi logging
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s - %(levelname)s - %(message)s",
filename="app.log"
)
def bagi(a, b):
try:
hasil = a / b
logging.info(f"Berhasil: {a} / {b} = {hasil}")
return hasil
except ZeroDivisionError as e:
logging.error(f"Error pembagian: {e}")
raise
except TypeError as e:
logging.error(f"Error tipe data: {e}")
raise
# Penggunaan
try:
bagi(10, 0)
except ZeroDivisionError:
print("Terjadi kesalahan!")
Best Practices¶
1. Spesifik dalam Menangkap Exception¶
# Buruk - terlalu umum
try:
...
except:
pass
# Baik - spesifik
try:
...
except ValueError:
...
except TypeError:
...
2. Jangan Mengabaikan Exception¶
# Buruk
try:
operasi_penting()
except:
pass
# Baik
try:
operasi_penting()
except SomeError as e:
logging.error(f"Gagal: {e}")
# Atau re-raise
raise
3. Gunakan finally untuk Cleanup¶
resource = acquire_resource()
try:
use_resource(resource)
finally:
release_resource(resource)
# Atau lebih baik dengan context manager
with acquire_resource() as resource:
use_resource(resource)
4. Berikan Pesan Error yang Jelas¶
# Buruk
raise ValueError("Error!")
# Baik
raise ValueError(f"Nilai '{nilai}' harus berupa integer positif")
Contoh Praktis¶
Validasi Input User¶
def minta_angka(prompt, min_val=None, max_val=None):
while True:
try:
nilai = float(input(prompt))
if min_val is not None and nilai < min_val:
raise ValueError(f"Nilai minimal adalah {min_val}")
if max_val is not None and nilai > max_val:
raise ValueError(f"Nilai maksimal adalah {max_val}")
return nilai
except ValueError as e:
print(f"Input tidak valid: {e}")
umur = minta_angka("Masukkan umur: ", min_val=0, max_val=150)
Retry dengan Backoff¶
import time
def dengan_retry(func, max_attempts=3, delay=1):
for attempt in range(max_attempts):
try:
return func()
except Exception as e:
if attempt == max_attempts - 1:
raise
print(f"Attempt {attempt + 1} gagal: {e}")
time.sleep(delay * (attempt + 1))
# Penggunaan
def operasi_tidak_stabil():
import random
if random.random() < 0.7:
raise ConnectionError("Koneksi terputus")
return "Sukses!"
try:
hasil = dengan_retry(operasi_tidak_stabil)
print(hasil)
except ConnectionError:
print("Gagal setelah semua retry")
Latihan¶
Buat fungsi yang membaca file dan menangani berbagai kemungkinan error
Buat custom exception untuk validasi data mahasiswa
Buat decorator untuk menangani exception dan melakukan logging
Implementasikan retry mechanism untuk koneksi database