CSV dan JSON

Memproses CSV dengan modul csv dan JSON dengan json.load/dump.

Daftar isi

CSV dan JSON adalah dua format pertukaran data yang paling sering ditemui ketika program perlu membaca data dari luar dirinya. Modul csv menangani tabel berupa baris dan kolom yang dipisahkan tanda koma, sedangkan modul json menangani teks terstruktur yang meniru struktur data Python. Topik ini membahas pembacaan dan penulisan kedua format tersebut, termasuk pilihan pemformatan yang menjaga berkas tetap terbaca dan konsisten lintas platform.

Membaca CSV dengan csv.reader#

Modul csv membaca berkas yang sudah terbuka dan mengubah setiap barisnya menjadi list berisi string. Berkas dibuka dengan argumen newline="" dan encoding="utf-8", lalu objek berkasnya diteruskan ke csv.reader(). Setiap baris menghasilkan satu list, dan seluruh nilai di dalamnya bertipe string tanpa kecuali, sehingga angka perlu dikonversi secara terpisah.

python baca-csv.py
import csv
from pathlib import Path

Path("nilai.csv").write_text(
    "nama,nilai\nAli,78\nBudi,65\nCitra,91\n",
    encoding="utf-8",
)
with open("nilai.csv", newline="", encoding="utf-8") as f:
    for baris in csv.reader(f):
        print(baris)
text Keluaran
['nama', 'nilai']
['Ali', '78']
['Budi', '65']
['Citra', '91']

Argumen newline="" mencegah baris kosong tambahan yang muncul pada sebagian platform ketika berkas dibuka dengan mode teks biasa. Baris pertama pada contoh di atas adalah baris header, dan modul csv memperlakukannya seperti baris data biasa, sehingga penanganannya tetap menjadi tanggung jawab program. Nilai 78 tiba sebagai string '78', dan konversi angkanya dilakukan dengan int() pada saat nilai itu benar-benar dipakai.

DictReader dan penulisan CSV#

Kelas csv.DictReader memetakan baris header menjadi kunci dictionary, sehingga setiap baris berikutnya dibaca sebagai dictionary berisi pasangan nama kolom dan nilainya. Pada sisi penulisan, kelas csv.DictWriter menerima daftar fieldnames, lalu menulis header dengan writeheader() dan seluruh baris dengan writerows(). Bentuk ini menghindari kesalahan urutan kolom karena setiap nilai dikenali berdasarkan namanya, bukan posisinya.

python Contoh: DictReader dan DictWriter
import csv
from pathlib import Path

with open("nilai.csv", newline="", encoding="utf-8") as f:
    for baris in csv.DictReader(f):
        print(baris["nama"], int(baris["nilai"]) + 2)

siswa_baru = [
    {"nama": "Dewi", "nilai": 88},
    {"nama": "Eko", "nilai": 74},
]
with open("baru.csv", "w", newline="", encoding="utf-8") as f:
    penulis = csv.DictWriter(f, fieldnames=["nama", "nilai"])
    penulis.writeheader()
    penulis.writerows(siswa_baru)
print(Path("baru.csv").read_text(encoding="utf-8"), end="")
text Keluaran
Ali 80
Budi 67
Citra 93
nama,nilai
Dewi,88
Eko,74

Pembacaan melalui DictReader memperlihatkan bahwa konversi int() tetap diperlukan sebelum nilai dihitung, karena format CSV tidak menyimpan tipe apa pun. Hasil penulisan pada bagian akhir keluaran menunjukkan format yang persis sama dengan berkas contoh pada bagian sebelumnya, yaitu header diikuti baris data yang dipisahkan koma. Apabila sebuah nilai mengandung tanda koma, modul csv membungkusnya dengan tanda kutip secara otomatis dan menguraikannya kembali dengan benar saat dibaca.

JSON sebagai teks terstruktur#

Format JSON menyimpan data dalam teks yang meniru struktur data umum, dengan pemetaan yang ditetapkan secara resmi, yaitu object menjadi dict, array menjadi list, dan nilai true, false, null menjadi True, False, None. Fungsi json.dumps() mengubah objek Python menjadi string JSON, sedangkan json.loads() menguraikan string tersebut kembali menjadi objek. Perulangan bolak-balik ini disebut roundtrip dan menjadi cara ringkas menguji bahwa struktur data dapat direpresentasikan dengan aman.

python Contoh: dumps dan loads
import json

bacaan = {"sensor": "suhu-01", "nilai": [28.5, 29.0, 27.8], "aktif": True}
teks = json.dumps(bacaan)
print(teks)
hasil = json.loads(teks)
print(hasil["aktif"], len(hasil["nilai"]))
print(round(sum(hasil["nilai"]) / len(hasil["nilai"]), 2))
text Keluaran
{"sensor": "suhu-01", "nilai": [28.5, 29.0, 27.8], "aktif": true}
True 3
28.43

Nilai True Python ditulis sebagai true pada teks JSON, dan konversi baliknya mengembalikan True tanpa kehilangan tipe. Secara bawaan, fungsi json.dumps() mengubah seluruh karakter non-ASCII menjadi urutan pelarian seperti \u00e4, sehingga teksnya tetap valid pada platform mana pun, meskipun sedikit sulit dibaca. Argumen ensure_ascii=False mematikan perilaku tersebut agar karakter aslinya tetap tercetak.

python Contoh: pengaruh ensure_ascii
import json

coba = {"deskripsi": "kopi à 25 ribu"}
print(json.dumps(coba))
print(json.dumps(coba, ensure_ascii=False))
text Keluaran
{"deskripsi": "kopi \u00e0 25 ribu"}
{"deskripsi": "kopi à 25 ribu"}

Kedua bentuk keluaran di atas menghasilkan dictionary yang identik setelah diuraikan kembali, sehingga pilihannya murni perkara keterbacaan berkas. Untuk berkas yang juga dibaca manusia, ensure_ascii=False dipilih, dan berkasnya tetap disimpan dengan encoding="utf-8" agar karakternya tersimpan dengan benar.

Fungsi json.dump() dan json.load() bekerja langsung pada objek berkas, dengan urutan argumen yang berbeda dari varian json.dumps() dan json.loads(), yaitu objek data terlebih dahulu dan objek berkasnya kemudian. Argumen indent=2 membuat setiap tingkat struktur ditulis pada baris tersendiri, sehingga berkasnya mudah dibaca dan mudah dibandingkan antar versi. Pembacaannya memakai satu pemanggilan json.load() yang mengembalikan seluruh isi berkas sebagai objek Python.

python Contoh: json.dump dan json.load pada berkas
import json
from pathlib import Path

pengaturan = {"tema": "gelap", "ukuran_font": 14, "bahasa": "id"}
with open("pengaturan.json", "w", encoding="utf-8") as f:
    json.dump(pengaturan, f, indent=2, ensure_ascii=False)
print(Path("pengaturan.json").read_text(encoding="utf-8"))
with open("pengaturan.json", encoding="utf-8") as f:
    hasil = json.load(f)
print(hasil["tema"], hasil["ukuran_font"])
text Keluaran
{
  "tema": "gelap",
  "ukuran_font": 14,
  "bahasa": "id"
}
gelap 14

Berkas yang ditulis dengan indentasi memuat spasi tambahan sebagai bagian formatnya, dan bagian itu tidak mengubah data sama sekali saat dibaca kembali. Bentuk tanpa indent menghemat ukuran berkas dan lazim dipakai untuk data yang hanya dibaca program, sedangkan bentuk berindentasi dipilih untuk berkas pengaturan yang sesekali disunting manusia. Pilihan ini menjadikan JSON format yang lazim untuk berkas pengaturan, karena strukturnya dapat bersarang secara bebas dan teksnya tetap terbaca tanpa alat bantu khusus.

Kesalahan umum#

Kesalahan pertama adalah menganggap JSON mendukung semua tipe Python. Format ini hanya mengenal tipe terbatas, dan objek di luar daftar tersebut ditolak dengan error TypeError, seperti terlihat pada objek tanggal berikut.

python Contoh: objek yang tidak didukung JSON
import json
from datetime import date

try:
    json.dumps({"tanggal": date(2026, 11, 2)})
except TypeError as e:
    print(type(e).__name__, e)
text Keluaran
TypeError Object of type date is not JSON serializable

Perbaikannya adalah mengubah tanggal menjadi string sebelum ditulis, misalnya melalui date.isoformat(), lalu menguraikannya kembali saat dibaca. Kesalahan kedua adalah mengira nilai CSV sudah bertipe angka, padahal seluruhnya string, sehingga perhitungan langsung atas hasil pembacaan menimbulkan TypeError. Kesalahan ketiga adalah melupakan newline="" saat membuka berkas CSV, yang pada sebagian platform menghasilkan baris kosong tambahan di antara baris data. Kesalahan terakhir adalah menulis JSON tanpa indent untuk berkas yang akan dibaca manusia, sehingga seluruh isi berkas menumpuk pada satu baris yang panjang dan sulit dibandingkan antar revisi.

Ringkasan#

  • csv.reader() menghasilkan list string per baris, sedangkan csv.DictReader() memetakan baris ke dictionary berdasarkan baris header.
  • Berkas CSV dibuka dengan newline="" dan encoding="utf-8", dan seluruh nilainya bertipe string hingga dikonversi secara eksplisit.
  • json.dumps() dan json.loads() mengonversi antara objek Python dan teks JSON, sedangkan json.dump() dan json.load() bekerja langsung pada berkas.
  • Argumen indent dan ensure_ascii=False menjadikan berkas JSON lebih mudah dibaca tanpa mengubah datanya.

Referensi#