Comprehension adalah sintaks Python untuk membangun list, dictionary, atau set baru dari sebuah iterable dalam satu ekspresi. Pola bacaannya selalu sama, yaitu ekspresi terlebih dahulu, lalu klausa for, lalu kondisi penyaringan apabila ada. Topik ini membahas list comprehension sebagai fondasinya, kondisi penyaringan dan pemilihan nilai, varian dictionary dan set, comprehension bersarang, serta batas keterbacaannya.
List comprehension sebagai alternatif perulangan#
Cara klasik membangun list baru adalah mendeklarasikan list kosong, menjalankan perulangan for, lalu memanggil append() pada setiap putaran. List comprehension memadatkan ketiga langkah itu menjadi satu baris dengan bentuk [ekspresi for variabel in iterable].
kuadrat = []
for n in range(1, 6):
kuadrat.append(n * n)
print(kuadrat)
kuadrat2 = [n * n for n in range(1, 6)]
print(kuadrat2)[1, 4, 9, 16, 25]
[1, 4, 9, 16, 25]Kedua pendekatan menghasilkan list kuadrat yang sama persis. Versi comprehension menyingkat tiga baris menjadi satu, dan variabel n tidak tersisa setelah ekspresinya selesai, sehingga tidak bocor ke lingkup (scope) di sekitarnya. Perbedaan ini murni gaya penulisan, sebab mekanisme perulangannya sama.
Cara membacanya mengikuti urutan penulisannya, yaitu untuk setiap n dalam range(1, 6), hasilkan n * n. Ekspresi di depan boleh berupa panggilan fungsi, perhitungan, atau pemilihan nilai, selama menghasilkan satu nilai per elemen. Nama variabel hasil sebaiknya menggambarkan isi list, misalnya kuadrat untuk list berisi kuadrat, sehingga baris comprehension dapat dipahami tanpa membaca klausanya.
Kondisi penyaringan dan pemilihan nilai#
Kondisi if di akhir klausa for menyaring elemen yang boleh masuk, sedangkan ekspresi if dengan else di awal mengubah nilai per elemen. Keduanya terlihat mirip tetapi berbeda peran, yaitu satu memutuskan boleh masuk atau tidak, sedangkan yang lain memutuskan nilai apa yang dihasilkan.
nilai = [78, 92, 65, 88, 55]
lulus = [n for n in nilai if n >= 70]
print(lulus)
label = ["lulus" if n >= 70 else "tidak" for n in nilai]
print(label)[78, 92, 88]
['lulus', 'lulus', 'tidak', 'lulus', 'tidak']Baris pertama menyaring, sehingga hanya 78, 92, dan 88 yang masuk. Baris kedua tidak menyaring apa pun, karena seluruh lima elemen tetap terwakili, tetapi nilainya diubah menjadi label. Mengetahui posisi kedua bentuk ini mencegah kebingungan saat membaca comprehension yang ditulis orang lain.
Kedua bentuk kondisi dapat digabung dalam satu comprehension, misalnya menyaring dahulu dengan if, lalu mengubah nilai tersisa dengan pasangan if dan else. Lebih dari satu klausa if juga sah dan bekerja sebagaimana dua penyaringan berurutan. Meskipun demikian, setiap lapis kondisi tambahan menambah beban baca, sehingga gabungan yang panjang lebih baik ditulis sebagai perulangan.
Dict dan set comprehension#
Bentuk tanda kurung kurawal menghasilkan dictionary apabila ekspresinya berupa pasangan kunci: nilai, dan menghasilkan set apabila ekspresinya nilai tunggal. Aturan keunikan dan syarat hashable yang berlaku pada kedua struktur tersebut tetap berlaku pada comprehensionnya.
nama = ["Ali", "Budi", "Citra"]
panjang = {n: len(n) for n in nama}
print(panjang)
huruf = {h.lower() for h in "AABBCC"}
print(sorted(huruf)){'Ali': 3, 'Budi': 4, 'Citra': 5}
['a', 'b', 'c']Dict comprehension membuat pemetaan nama ke panjangnya, sedangkan set comprehension menyaring enam huruf besar menjadi tiga huruf kecil yang unik. Cetakan set tetap melalui sorted() karena urutan iterasi set tidak dijamin oleh bahasa.
Sumber data dict comprehension tidak harus satu list tunggal. Fungsi zip() menyatukan dua list menjadi pasangan, dan {k: v for k, v in zip(kunci, nilai)} memetakannya menjadi dictionary dalam satu baris. Pola ini sering muncul saat dua urutan data sejajar, misalnya daftar nama dan daftar nilainya.
Comprehension bersarang#
Comprehension dapat memuat lebih dari satu klausa for, dan klausa yang lebih kanan menjadi putaran dalam. Pola ini lazim untuk meratakan list bersarang menjadi satu dimensi.
matriks = [[1, 2, 3], [4, 5, 6]]
semua_elemen = [x for baris in matriks for x in baris]
print(semua_elemen)[1, 2, 3, 4, 5, 6]Urutan klausanya mengikuti urutan perulangan biasa, yaitu for baris in matriks terlebih dahulu, lalu for x in baris. Kesalahan yang sering terjadi adalah menukar keduanya, dan hasilnya pesan NameError karena baris belum terdefinisi pada putaran pertama.
Comprehension bersarang memiliki dua bentuk yang perlu dibedakan. Bentuk dengan dua klausa for meratakan struktur, sedangkan comprehension di dalam ekspresi, misalnya [[x for x in baris] for baris in matriks], justru membangun struktur baru yang berlapis. Kedua pola sah digunakan, tetapi yang kedua lebih mudah salah baca dan biasanya cukup ditulis sebagai perulangan biasa.
Batas keterbacaan#
Segala yang dapat ditulis sebagai comprehension selalu dapat ditulis sebagai perulangan biasa, dan pertimbangan utamanya adalah keterbacaan. Comprehension yang membawa dua klausa for, satu kondisi, dan ekspresi panjang menjadi sulit diurai dalam sekali baca. PEP 8, panduan gaya resmi Python, menyarankan agar ekspresi kompleks tidak dipaksakan menjadi satu baris.
data = [[1, 2, 3], [4, 5, 6]]
hasil = [x * 2 for baris in data for x in baris if x % 2 == 1]
print(hasil)[2, 6, 10]Ekspresi di atas masih sanggup dibaca, tetapi satu penyaringan tambahan saja sudah membuatnya terlalu padat. Versi perulangan berikut menghasilkan keluaran yang sama dengan langkah yang dapat diikuti baris demi baris.
data = [[1, 2, 3], [4, 5, 6]]
hasil = []
for baris in data:
for x in baris:
if x % 2 == 1:
hasil.append(x * 2)
print(hasil)[2, 6, 10]Kedua versi menghasilkan [2, 6, 10], yaitu penggandaan dari nilai 1, 3, dan 5. Aturan praktis: pertahankan comprehension apabila jumlah klausanya sedikit dan ekspresinya pendek. Apabila logikanya bertingkat, pindah ke perulangan biasa.
Penilaian keterbacaan juga bergantung pada pembacanya, yaitu rekan satu tim yang mungkin belum terbiasa dengan bentuk ini. Comprehension dengan nama variabel hasil yang jelas membantu, tetapi penjelasan lewat komentar bukan pengganti penyederhanaan. Apabila satu baris membutuhkan komentar panjang agar dapat dipahami, baris itu sendiri yang perlu ditulis ulang.
Kesalahan umum#
Kesalahan pertama adalah menggunakan comprehension hanya untuk efek sampingnya, misalnya memanggil append() pada list lain di dalam ekspresinya. Hasil yang terkumpul berupa rentetan None, dan maksud semula tidak tercapai.
daftar = []
hasil = [daftar.append(n) for n in range(3)]
print(hasil)[None, None, None]Metode append() mengembalikan None, sehingga list hasil comprehension tidak memuat data apa pun. Kebutuhan seperti ini memang bukan kegunaan comprehension, dan perulangan biasa menyatakan maksud tersebut dengan lebih jelas.
Kesalahan kedua adalah lupa bahwa if pada posisi ekspresi wajib disertai else. Bentuk [n if n >= 70 for n in nilai] langsung ditolak sebagai error sintaks, karena ketika kondisinya salah, Python tidak memiliki nilai yang dapat dimasukkan. Pesan kesalahannya berupa SyntaxError, dan perbaikannya berupa penambahan bagian else atau pemindahan kondisi ke akhir klausa for. Kesimpulannya sederhana, yaitu pasangan if dan else untuk mengubah nilai, sedangkan if tanpa else di akhir untuk menyaring.
Ringkasan#
- Comprehension membangun list, dictionary, atau set baru dari sebuah iterable dalam satu ekspresi dengan pola ekspresi, klausa for, lalu kondisi.
- Kondisi
ifdi akhir menyaring elemen, sedangkan pasanganifdanelsepada posisi ekspresi mengubah nilai per elemen. - Klausa for tambahan menangani struktur bersarang, dan urutannya mengikuti perulangan biasa.
- Comprehension yang bertingkat dikembalikan ke perulangan biasa demi keterbacaan.
Referensi#
- List Comprehensions — Python Software Foundation — Bagian tutorial resmi yang mengenalkan comprehension untuk list, termasuk kondisi dan bentuk bersarangnya.
- PEP 8 — Python Software Foundation — Panduan gaya resmi Python yang menjadi rujukan batas keterbacaan ekspresi.