Pada pembagian np.array([1.0]) / np.array([0.0]), NumPy tidak melempar exception. Hasilnya inf plus satu RuntimeWarning, lalu eksekusi berlanjut seolah tidak terjadi apa-apa. Perilaku longgar ini nyaman saat eksplorasi data, tetapi kurang pas untuk perhitungan yang hasilnya dipakai mengambil keputusan — satu nan yang tidak terdeteksi bisa ikut tercetak di laporan akhir.
Bab ini membahas kendali di tingkat global: np.geterr() untuk membaca kebijakan error floating-point yang sedang berlaku, np.seterr() untuk mengubahnya dengan salah satu dari empat mode (ignore, warn, raise, call), dan pola aman penggunaannya. Kebijakan di lingkup lokal dengan np.errstate sudah diperkenalkan pada NaN dan Infinity; di sini fokusnya kebijakan yang berlaku lintas fungsi dan modul.
Perilaku Bawaan: Warning, Bukan Exception #
import numpy as np
import warnings
with warnings.catch_warnings(record=True) as terekam:
warnings.simplefilter("always")
pembilang = np.array([1.0, 0.0, 2.0])
penyebut = np.array([0.0, 0.0, 0.0])
hasil = pembilang / penyebut
print("hasil:", hasil)
for w in terekam:
print(w.category.__name__, "->", w.message)Output yang Dihasilkan:
hasil: [inf nan inf]
RuntimeWarning -> divide by zero encountered in divide
RuntimeWarning -> invalid value encountered in divideMari kita bedah:
- Baris 4-9: blok
warnings.catch_warningsmerekam peringatan agar bisa dicetak sebagai output teruji — tanpa itu,RuntimeWarninghanya muncul di stderr dan tidak terlihat lewatprint. - Baris 10 (
hasil):1.0/0.0menghasilkaninf,0.0/0.0menghasilkannan; program tidak berhenti di baris mana pun. - Baris 11-12: dua
RuntimeWarningtercatat —divide by zerountuk pembagian dengan nol,invalid valueuntuk operasi tak terdefinisi.
Intinya: mode bawaan NumPy adalah warn. Interpreter memberi tahu lewat peringatan, menghasilkan nilai khusus (inf/nan), lalu melanjutkan. Mengapa nilai-nilai itu menular ke hasil agregasi sudah dibahas pada NaN dan Infinity.
Membaca dan Mengubah Kebijakan: geterr dan seterr #
np.geterr() mengembalikan kamus kebijakan per jenis kesalahan: divide (pembagian nol), over (overflow), under (underflow), dan invalid (operasi tak terdefinisi). np.seterr() mengubah kebijakan itu dan — penting — mengembalikan kebijakan sebelumnya, sehingga perubahan selalu bisa dibatalkan.
| Mode | Perilaku saat kesalahan terjadi |
|---|---|
ignore | Tanpa pesan; hasil inf/nan tetap dikembalikan |
warn (bawaan) | RuntimeWarning dicetak; hasil inf/nan tetap |
raise | FloatingPointError dilempar; eksekusi berhenti di baris itu |
call | Fungsi handler dipanggil; eksekusi berlanjut |
import numpy as np
print(np.geterr())
saved = np.seterr(divide='ignore', invalid='ignore')
print(np.float64(1.0) / np.float64(0.0), np.float64(0.0) / np.float64(0.0))
np.seterr(**saved)
print(np.geterr())Output yang Dihasilkan:
{'divide': 'warn', 'over': 'warn', 'under': 'ignore', 'invalid': 'warn'}
inf nan
{'divide': 'warn', 'over': 'warn', 'under': 'ignore', 'invalid': 'warn'}Mari kita urai:
- Baris 2: kebijakan bawaan —
divide,over, daninvalidbernilaiwarn, sedangkanundersudahignorekarena underflow jarang memengaruhi hasil secara berarti. - Baris 3 (
saved = ...):np.seterrmengembalikan kebijakan lama dan kita simpan; baris 4 kemudian memaksa pembagian nol dan0.0/0.0berjalan tanpa satu pun pesan —infdannantetap dihasilkan, hanya pengumumannya yang ditiadakan. - Baris 5 (
np.seterr(**saved)): kebijakan bawaan dikembalikan persis seperti semula — inilah pola simpan-restore yang wajib untuk kebijakan global.
Kebijakan raise untuk Data Kritis #
Bila hasil perhitungan menentukan — rekonsiliasi keuangan, laporan yang dikirim otomatis, pipeline tanpa pengawasan manusia — satu nan yang lolos jauh lebih mahal daripada program yang berhenti lebih awal. Mode all='raise' membuat setiap kesalahan floating-point melempar FloatingPointError tepat di baris penyebabnya:
import numpy as np
saved = np.seterr(all='raise')
try:
print(np.array([1.0]) / np.array([0.0]))
except FloatingPointError as e:
print("FloatingPointError:", e)
finally:
np.seterr(**saved)
print("policy divide:", np.geterr()['divide'])Output yang Dihasilkan:
FloatingPointError: divide by zero encountered in divide
policy divide: warnPembacaannya: pembagian 1.0/0.0 tidak lagi menghasilkan inf, tetapi melempar FloatingPointError yang pesannya sama dengan RuntimeWarning versi warn. Blok try/except menangkap error itu sehingga skrip tetap berjalan dan pesannya tercetak sebagai bukti, sedangkan finally menjamin kebijakan lama dikembalikan apa pun yang terjadi di dalam try.
Mode call: Handler Kustom #
Mode call menyerahkan penanganan kesalahan kepada fungsi milik kita: NumPy memanggil handler setiap kali kesalahan terjadi, lalu melanjutkan eksekusi seperti mode ignore. Handler didaftarkan lewat np.seterrcall:
import numpy as np
def laporkan(jenis, flag):
print("handler:", jenis, "|", flag)
sebelumnya = np.seterrcall(laporkan)
saved = np.seterr(divide='call')
print(np.float64(1.0) / np.float64(0.0))
np.seterr(**saved)
np.seterrcall(sebelumnya)
print("divide:", np.geterr()['divide'])Output yang Dihasilkan:
handler: divide by zero | 1
inf
divide: warnMari kita urai:
- Baris 6 (
np.seterrcall): mendaftarkanlaporkansebagai handler dan mengembalikan callback sebelumnya — disimpan agar bisa dikembalikan di akhir. - Baris 8: saat pembagian nol terjadi, handler dipanggil dengan dua argumen: string jenis kesalahan (
divide by zero) dan kode flag floating-point. Hasil operasinya tetapinf, dan program berlanjut. - Baris 9-10: kebijakan dan callback dikembalikan ke keadaan awal; baris 11 membuktikan
dividekembali kewarn.
Pola ini cocok untuk pencatatan kejadian (log) ke berkas atau penghitung statistik kesalahan, yaitu ketika kesalahan perlu diketahui tetapi tidak boleh menghentikan proses batch.
Recap errstate: Kebijakan Lokal dengan with #
Sebagai recap singkat dari NaN dan Infinity: np.errstate memberi kebijakan yang hanya berlaku di dalam blok with, lalu dikembalikan secara otomatis tanpa simpan-restore manual. Untuk perlindungan yang lingkupnya lokal, itu tetap pilihan paling aman; np.seterr berguna ketika kebijakan harus menjangkau fungsi-fungsi pustaka yang kodenya tidak kita ubah. Kedua pendekatan bisa digabung — misalnya fungsi validasi kecil yang mempertajam kebijakan hanya selama badannya berjalan, pola yang melengkapi strategi pada Penanganan Data Numerik yang Tidak Valid:
import numpy as np
def rasio_tervalidasi(a, b):
with np.errstate(divide='raise', invalid='raise'):
return a / b
print(rasio_tervalidasi(np.array([10.0, 30.0]), np.array([2.0, 4.0])))
try:
print(rasio_tervalidasi(np.array([0.0]), np.array([0.0])))
except FloatingPointError as e:
print("FloatingPointError:", e)Output yang Dihasilkan:
[5. 7.5]
FloatingPointError: invalid value encountered in divideRasio normal dihitung seperti biasa ([5. 7.5]), sedangkan 0.0/0.0 di dalam fungsi memicu FloatingPointError berpesan invalid value encountered in divide. Di luar fungsi, kebijakan global tidak pernah berubah — pembaca kode bisa memercayai bahwa fungsi tersebut membersihkan keadaannya sendiri.
Pedoman ringkasnya: biarkan bawaan warn saat eksplorasi, pakai np.errstate untuk lingkup lokal, dan pakai np.seterr(all='raise') hanya dengan pola simpan-restore pada bagian yang memproses data kritis.