Ketika hasil program tidak sesuai harapan, teknik debugging tercepat adalah menyisipkan print() untuk mengintip nilai variabel di titik-titik mencurigakan. Tidak perlu alat tambahan, tidak perlu proses instalasi apa pun — cukup satu baris kode dan jalankan ulang programnya. Pada Chapter ini kita akan mempelajari cara memakai print() secara efektif, dari melacak nilai antar baris sampai trik f-string {var=}, lalu mengenali kapan teknik ini justru mulai menghambat pekerjaan kita.
Melacak Nilai dengan print() #
Ide dasarnya sederhana: jika program menghasilkan hasil yang salah, sisipkan print() di sekitar kode yang dicurigai untuk melihat nilai variabel sebelum dan sesudahnya. Ketika nilai yang dicetak masih benar pada print pertama tetapi salah pada print kedua, berarti sumber masalah terletak di antara keduanya. Perhatikan contoh berikut yang menghitung rata-rata nilai ujian:
nilai_ujian = [80, 90, 75]
print("DEBUG: nilai_ujian =", nilai_ujian)
hasil = sum(nilai_ujian) / (len(nilai_ujian) - 1)
print("DEBUG: hasil =", hasil)
print("Rata-rata:", hasil)Output yang Dihasilkan:
DEBUG: nilai_ujian = [80, 90, 75]
DEBUG: hasil = 122.5
Rata-rata: 122.5Mari kita telaah peran setiap baris:
- Baris 2 (
print("DEBUG: nilai_ujian =", ...)): mencetak isi list sebelum diolah. Nilainya benar, jadi masalah bukan pada data masukannya. - Baris 4 (
hasil = sum(...)): menghitung jumlah nilai dibagilen(nilai_ujian) - 1, yaitu245 / 2. - Baris 5 (
print("DEBUG: hasil =", hasil)): mencetak hasil122.5— seharusnya rata-rata tiga nilai adalah81.666.... Karena input benar tetapi hasil salah, kesalahan pasti ada di baris 4, dan memang pembagi yang dipakai adalahlen() - 1.
Awalan DEBUG: pada pesan membuat baris diagnosis mudah dibedakan dari output program yang sesungguhnya, sekaligus memudahkan pencarian saat baris tersebut lupa dihapus.
Label Otomatis dengan f-string {var=} #
Menulis print("DEBUG: nama_variabel =", nama_variabel) terasa repetitif karena nama variabel ditulis dua kali. Sejak Python 3.8, f-string menyediakan specifier {var=} yang otomatis mencetak nama variabel, tanda sama dengan, lalu nilainya:
nama = "Budi"
saldo = 125000
print(f"{nama=}")
print(f"{saldo=}")
print(f"{saldo * 2=}")
print(f"{saldo = }")Output yang Dihasilkan:
nama='Budi'
saldo=125000
saldo * 2=250000
saldo = 125000Specifier ini juga bekerja untuk ekspresi seperti {saldo * 2=}, sehingga kita bisa memeriksa hasil perhitungan tengah tanpa membuat variabel sementara. Spasi di sekitar tanda = dipertahankan apa adanya — perhatikan {saldo = } yang menghasilkan saldo = 125000.
repr() untuk Melihat Nilai Sebagaimana Adanya #
print() memanggil str() pada setiap object yang dicetak, dan untuk beberapa tipe hasilnya bisa menipu. Nilai string "1" dan angka 1 tercetak sama persis, padahal keduanya tidak pernah sama di mata operator perbandingan. Fungsi repr() menampilkan representasi tanpa ambigu yang lebih cocok untuk diagnosis:
nilai = "1"
print(nilai)
print(repr(nilai))
teks = "Kopi Gayo"
print(str(teks))
print(repr(teks))
print([teks, 3.5])Output yang Dihasilkan:
1
'1'
Kopi Gayo
'Kopi Gayo'
['Kopi Gayo', 3.5]Mari kita perhatikan perilakunya:
- Baris 3 (
print(nilai)): string"1"tercetak sebagai1— terlihat seperti angka. - Baris 4 (
print(repr(nilai))):repr()menambahkan tanda kutip sehingga terlihat jelas bahwa nilainya adalah string'1', bukan angka. Inilah alasan perbandingannilai == 1bernilaiFalse. - Baris 9 (
print([teks, 3.5])): isi container seperti list memang memakairepr()untuk setiap elemennya, itulah mengapa elemen stringnya tampil dengan tanda kutip.
Dalam f-string, konversi !r memberi efek yang sama: f"{nilai!r}" menghasilkan '1'.
Kapan print() Mulai Menghambat #
Debugging dengan print() cepat untuk kasus sederhana, tetapi tiga kelemahan muncul seiring program membesar:
- Banjiran di dalam loop — satu
print()di dalam loop yang berjalan ribuan kali menghasilkan ribuan baris yang harus digulir untuk menemukan iterasi bermasalah. - Tanpa tingkat kepentingan — hasil diagnosis, pesan operasional, dan error fatal tercampur rata; tidak ada cara mematikan yang satu tanpa yang lain.
- Tertinggal di kode produksi —
print()yang lupa dihapus ikut tercetak di hadapan pengguna akhir.
Satu perbaikan kecil yang layak diadopsi: kirim hasil diagnosis ke stderr agar terpisah dari output utama program di stdout. Simpan sebagai aplikasi.py:
import sys
for i in range(1, 4):
print(f"DEBUG: memproses baris {i}", file=sys.stderr)
print("Laporan selesai: 3 baris")Parameter file=sys.stderr mengarahkan pesan ke stream stderr. Manfaatnya terlihat saat pengalihan stream di terminal:
python3 aplikasi.py 2> debug.logOutput yang Dihasilkan:
Laporan selesai: 3 barisBerkas debug.log kini menampung seluruh baris DEBUG: tanpa mencemari hasil laporan, dan perintah cat debug.log akan menampilkan ketiga barisnya.