Kursus Python / Menyimpan, membaca, dan memvalidasi data JSON
JSON (JavaScript Object Notation) adalah format teks untuk pertukaran data terstruktur seperti object, array, string, dan angka. Fungsi json.load serta dump bekerja dengan objek berkas, sedangkan loads serta dumps digunakan untuk teks; format ini tidak mempertahankan semua jenis objek Python.
Hubungkan nilai JSON dengan tipe Python
| JSON | Python pada pembacaan biasa |
|---|---|
| object | dict |
| array | list |
| string | str |
| number | int atau float sesuai bentuk angka |
| true / false / null | True / False / None |
Kunci object dan string JSON memakai tanda kutip ganda. Komentar Python, kutip tunggal sebagai pembatas string, dan koma setelah unsur terakhir bukan bagian sintaks JSON biasa. Bedakan teks JSON true dari literal Python True ketika mengedit lokasi yang berbeda.
Tuple yang diserialisasi menjadi array dapat kembali sebagai list. Kunci dictionary numerik dapat menjadi string, sedangkan tanggal dan Decimal membutuhkan kebijakan konversi tersendiri. Karena itu, round trip JSON tidak menjamin tipe dan identitas objek Python asal tetap sama. Rujuk dokumentasi encoder dan decoder JSON Python untuk bentuk yang didukung.
Simpan record Unicode dan baca kembali
Gunakan folder latihan baru karena program mengganti expenses-demo.json. Simpan kode lengkap sebagai json_demo.py dengan encoding UTF-8. Jalankan python json_demo.py dalam lingkungan proyek dengan Python 3.12 atau lebih baru. Tidak diperlukan paket tambahan.
Nama contoh café dipertahankan untuk memperlihatkan karakter di luar ASCII. Kode mata uang merupakan data contoh dan tidak melakukan konversi jumlah.
import json
from pathlib import Path
data = {"currency": "KRW", "expenses": [{"name": "café", "amount": 8000}]}
path = Path("expenses-demo.json")
path.write_text(json.dumps(data, ensure_ascii=False, indent=2, allow_nan=False), encoding="utf-8")
loaded = json.loads(path.read_text(encoding="utf-8"))
amount = loaded["expenses"][0]["amount"]
if type(amount) is not int or amount < 0:
raise ValueError("invalid amount")
print(loaded["expenses"][0]["name"])
print(amount)
Keluaran yang diharapkan:
café
8000
dumps menghasilkan string JSON, lalu write_text menyimpannya ke berkas. Sebaliknya, read_text mengambil teks dan loads membentuk objek Python. ensure_ascii=False mempertahankan karakter non-ASCII yang dapat ditampilkan, sedangkan karakter yang wajib di-escape tetap di-escape. Encoding UTF-8 ditetapkan terpisah saat menulis dan membaca berkas.
indent=2 menata tampilan agar mudah dibaca tanpa mengubah arti data. Buka berkas dan periksa bahwa karakter é terbaca, lalu cocokkan jumlah 8000. Untuk memahami path dan penggantian isi yang terjadi, gunakan aturan pada latihan pathlib.
Pisahkan keberhasilan parsing dari validasi data
Parsing hanya memastikan teks dapat diinterpretasikan oleh decoder dengan pengaturan yang dipakai. Data masih mungkin tidak mempunyai kunci wajib, memakai array kosong, atau menempatkan string di lokasi angka. Contoh ini mengasumsikan struktur satu record yang diketahui; ia belum menjadi importer umum yang memeriksa seluruh struktur.
Pemeriksaan type(amount) is int sengaja menolak bool, meskipun isinstance(True, int) bernilai benar karena bool merupakan subclass int. Ia juga menolak 8000.0 dan "8000". Pilihan menerima subclass atau mengonversi angka lain harus ditetapkan sesuai kontrak, bukan diganti tanpa mempertimbangkan maknanya. Pemeriksaan rentang berikutnya menolak nilai negatif.
allow_nan=False menolak NaN dan Infinity saat serialisasi. Opsi penulisan ini tidak sekaligus membuat pembacaan input lain menjadi ketat. Python dapat menerima konstanta nonstandar itu pada decoder bawaan; untuk input ketat, tetapkan kebijakan parse_constant. Kunci object yang berulang juga memerlukan kebijakan, karena pembacaan bawaan mempertahankan nilai terakhir pada nama yang sama.
| Fungsi | Arah operasi |
|---|---|
load(file) |
Objek berkas → objek Python |
loads(text) |
Teks JSON → objek Python |
dump(obj, file) |
Objek Python → objek berkas teks |
dumps(obj) |
Objek Python → string JSON |
Memanggil dumps saja tidak membuat berkas. Demikian pula, memanggil dump beberapa kali ke berkas sama tidak otomatis membentuk satu array JSON yang sah. Pilih satu struktur dokumen atau format record yang memang ditentukan untuk pertukaran data Anda.
Uji nilai salah tanpa menyembunyikan penyebabnya
- Jalankan versi asli dan cocokkan dua baris keluaran. Periksa pula bahwa berkas berisi JSON yang ditata dengan dua spasi.
- Ubah angka 8000 pada dictionary Python menjadi
-1, lalu menjadiTrue, masing-masing pada eksekusi terpisah. Keduanya harus berhenti denganinvalid amount. Di teks JSON mentah, nilai boolean ditulistrue; di sumber Python ini gunakanTrue. - Ganti sementara angka dengan
float("nan"). Penulisan JSON ditolak olehallow_nan=Falsesebelum pemeriksaan jumlah pada hasil pembacaan. - Pulihkan 8000 dan jalankan lagi. Jangan hanya mengedit berkas JSON hasil lalu menjalankan seluruh contoh, karena tahap penulisan menimpa hasil edit sebelum pembacaan.
Teks JSON yang salah dapat menghasilkan JSONDecodeError. Perbaiki sintaks sumbernya; jangan mengganti parser dengan eval. Kesalahan berkas atau encoding perlu ditelusuri terpisah menurut aturan pembacaan teks. Untuk data luar yang besar, tetapkan pula batas ukuran masukan sesuai kemampuan aplikasi agar parsing tidak menghabiskan sumber daya tanpa batas.
Jika array expenses kosong, akses indeks nol gagal sebelum pemeriksaan amount. Importer umum harus memvalidasi tipe object, keberadaan kunci, tipe array, dan isi tiap record terlebih dahulu. Menangkap semua kesalahan dan menganggapnya jumlah nol akan menyembunyikan perbedaan data kosong dengan data rusak.




