CSV (comma-separated values) adalah format pertukaran data paling universal: ekspor Excel, hasil download dari sistem kantor, dataset untuk analisis. Formatnya tampak sederhana — nilai dipisah koma, baris dipisah baris baru — tetapi aturan sesungguhnya punya detail berbahaya. Chapter split() dan join() sudah memperlihatkan bagaimana split(",") hancur saat satu kolom berisi koma di dalam tanda kutip; module csv dari standard library menangani semua detail tersebut untuk kita.
writer dan reader #
Pasangan csv.writer dan csv.reader bekerja di atas berkas yang kita buka sendiri:
import csv
with open("penjualan.csv", "w", newline="", encoding="utf-8") as berkas:
penulis = csv.writer(berkas)
penulis.writerow(["nama", "produk", "jumlah"])
penulis.writerow(["Budi", "keyboard mekanik", 2])
penulis.writerow(["Siti", "mouse wireless", 1])
penulis.writerow(["Joko", "kabel USB-C, panjang 1 meter", 5])
with open("penjualan.csv", encoding="utf-8", newline="") as berkas:
pembaca = csv.reader(berkas)
for baris in pembaca:
print(baris)Output yang Dihasilkan:
['nama', 'produk', 'jumlah']
['Budi', 'keyboard mekanik', '2']
['Siti', 'mouse wireless', '1']
['Joko', 'kabel USB-C, panjang 1 meter', '5']Isi berkas penjualan.csv:
nama,produk,jumlah
Budi,keyboard mekanik,2
Siti,mouse wireless,1
Joko,"kabel USB-C, panjang 1 meter",5Mari kita bedah baris-baris kuncinya:
- Baris 3 (
with open("penjualan.csv", "w", newline="", encoding="utf-8") ...): berkas dibuka dengannewline=""— syarat wajib modulecsvpada mode teks. Modulecsvmengatur akhir barisnya sendiri; tanpanewline="", penerjemahan newline dari sistem operasi membuat akhir baris ganda di Windows (perilaku lengkapnya dibahas pada Chapter Encoding dan Newline). - Baris 4 (
penulis = csv.writer(berkas)): objectwriterdibuat di atas berkas yang sudah terbuka; semua penulisan lewat object ini. - Baris 8 (
penulis.writerow(["Joko", "kabel USB-C, panjang 1 meter", 5])): kolom yang mengandung koma otomatis dibungkus tanda kutip oleh writer, dan reader membongkarnya kembali menjadi satu nilai — inilah pekerjaan yang mustahil bagisplit(","). - Baris 10-12 (
pembaca = csv.reader(...)danfor baris in pembaca:): setiap baris terbaca sebagailiststring; angka2dan5yang kita tulis sebagaiintterbaca kembali sebagai"2"dan"5"— konversi ke angka tetap tugas kita, seperti saat membacainput().
Module csv menulis akhir baris sebagai \r\n sesuai standar RFC 4180 — pada blok isi berkas di atas, karakter \r memang tidak terlihat, tetapi karakter tersebut ada di dalam berkas.
DictWriter dan DictReader #
Bekerja dengan indeks kolom (baris[0], baris[1]) rapuh terhadap perubahan urutan. Pasangan DictWriter/DictReader memakai dictionary dengan kunci dari baris header:
import csv
stok = [
{"kode": "P001", "nama_barang": "beras 5 kg", "jumlah": 40},
{"kode": "P002", "nama_barang": "minyak goreng 1 L", "jumlah": 25},
]
with open("stok.csv", "w", newline="", encoding="utf-8") as berkas:
kolom = ["kode", "nama_barang", "jumlah"]
penulis = csv.DictWriter(berkas, fieldnames=kolom)
penulis.writeheader()
penulis.writerows(stok)
with open("stok.csv", encoding="utf-8", newline="") as berkas:
for baris in csv.DictReader(berkas):
print(baris)
print(baris["nama_barang"], "->", baris["jumlah"])Output yang Dihasilkan:
{'kode': 'P001', 'nama_barang': 'beras 5 kg', 'jumlah': '40'}
beras 5 kg -> 40
{'kode': 'P002', 'nama_barang': 'minyak goreng 1 L', 'jumlah': '25'}
minyak goreng 1 L -> 25DictWriter membutuhkan daftar nama kolom lewat fieldnames sebelum writeheader() menuliskan baris judul, dan writerows() menerima list of dictionary. Di sisi pembaca, DictReader otomatis menjadikan baris pertama sebagai kunci, sehingga baris["nama_barang"] jauh lebih terbaca daripada baris[1] dan tetap benar walau urutan kolom berubah.
Delimiter dan Dialect #
Tidak semua CSV memakai koma. Berkas dari regional Eropa (yang memakai koma sebagai tanda desimal) lazim memakai titik koma:
import csv
with open("penjualan-titik-koma.csv", "w", newline="", encoding="utf-8") as berkas:
penulis = csv.writer(berkas, delimiter=";")
penulis.writerow(["kota", "total"])
penulis.writerow(["Jakarta", 1500])
penulis.writerow(["Bandung", 900])
print(open("penjualan-titik-koma.csv", encoding="utf-8").read(), end="")
with open("penjualan-titik-koma.csv", encoding="utf-8", newline="") as berkas:
pembaca = csv.reader(berkas, delimiter=";")
for baris in pembaca:
print(baris)Output yang Dihasilkan:
kota;total
Jakarta;1500
Bandung;900
['kota', 'total']
['Jakarta', '1500']
['Bandung', '900']Kombinasi aturan — delimiter, aturan kutip, akhir baris — bisa juga dipilih sekaligus lewat dialect bawaan seperti csv.excel (default) atau csv.excel_tab yang memakai tab, dan dialect kustom bisa didaftarkan lewat csv.register_dialect(). Dalam praktik, menyetel delimiter satu per satu seperti di atas sudah menutup mayoritas kebutuhan.
Aturan Kutip #
Konstanta quoting mengendalikan kapan writer membungkus nilai dengan tanda kutip:
| Konstanta | Perilaku saat menulis |
|---|---|
csv.QUOTE_MINIMAL (default) | hanya mengutip nilai yang perlu (mengandung koma, kutip, atau baris baru) |
csv.QUOTE_ALL | mengutip semua nilai |
csv.QUOTE_NONNUMERIC | mengutip semua nilai non-angka |
csv.QUOTE_NONE | tidak pernah mengutip (gagal bila nilai memuat delimiter) |
QUOTE_NONNUMERIC punya bonus manis di sisi pembaca — angka yang tidak dikutip otomatis dikonversi menjadi float:
import csv
with open("produk.csv", "w", newline="", encoding="utf-8") as berkas:
penulis = csv.writer(berkas, quoting=csv.QUOTE_NONNUMERIC)
penulis.writerow(["nama", "harga", "stok"])
penulis.writerow(["gula pasir", 16500, 120])
penulis.writerow(["tepung terigu", 12000, 85])
print(open("produk.csv", encoding="utf-8").read(), end="")
with open("produk.csv", encoding="utf-8", newline="") as berkas:
for baris in csv.reader(berkas, quoting=csv.QUOTE_NONNUMERIC):
print([type(nilai).__name__ for nilai in baris], baris)Output yang Dihasilkan:
"nama","harga","stok"
"gula pasir",16500,120
"tepung terigu",12000,85
['str', 'str', 'str'] ['nama', 'harga', 'stok']
['str', 'float', 'float'] ['gula pasir', 16500.0, 120.0]
['str', 'float', 'float'] ['tepung terigu', 12000.0, 85.0]Baris judul terbaca sebagai str karena semua nilainya dikutip, sedangkan kolom angka terbaca sebagai float. Perhatikan konsekuensinya: harga 16500 menjadi 16500.0, sehingga mode ini paling pas untuk data yang memang pecahan.