Perulangan #
Perulangan adalah mekanisme untuk mengeksekusi blok kode berulang kali. Python memiliki dua konstruksi perulangan utama — for dan while — tapi cara Python menggunakannya berbeda cukup signifikan dari bahasa seperti C, Java, atau JavaScript. Di Python, for loop bukan loop berbasis indeks, melainkan loop berbasis iterasi langsung atas elemen. Paradigma ini, digabung dengan built-in seperti enumerate, zip, dan comprehension, membuat kode perulangan Python jauh lebih ekspresif dan ringkas. Artikel ini membahas cara idiomatis menulis perulangan di Python — termasuk anti-pattern yang sering dibawa dari kebiasaan bahasa lain.
for Loop
#
for loop di Python mengiterasi langsung atas elemen dari objek iterable — list, tuple, string, dict, set, generator, atau objek apapun yang mengimplementasikan protokol iterasi.
# Iterasi langsung — cara Python
buah = ["apel", "jeruk", "mangga"]
for item in buah:
print(item)
# → apel
# → jeruk
# → mangga
# Iterasi string — karakter per karakter
for huruf in "Python":
print(huruf, end=" ")
# → P y t h o n
# Iterasi tuple
for x, y in [(1, 2), (3, 4), (5, 6)]: # unpacking langsung
print(f"x={x}, y={y}")
# Iterasi set (urutan tidak dijamin)
for warna in {"merah", "hijau", "biru"}:
print(warna)
Anti-Pattern: Iterasi via Indeks #
Kesalahan paling umum developer yang baru pindah ke Python adalah menggunakan indeks untuk iterasi — gaya yang lazim di C/Java tapi tidak idiomatis di Python:
buah = ["apel", "jeruk", "mangga"]
# ANTI-PATTERN: iterasi via indeks — tidak perlu di Python
for i in range(len(buah)):
print(buah[i])
# BENAR: iterasi langsung atas elemen
for item in buah:
print(item)
range() — Membuat Urutan Angka
#
range() menghasilkan urutan angka secara lazy (tidak membuat list di memori). Tersedia dalam tiga bentuk:
# range(stop) — mulai dari 0, sampai stop-1
for i in range(5):
print(i, end=" ")
# → 0 1 2 3 4
# range(start, stop) — mulai dari start, sampai stop-1
for i in range(2, 8):
print(i, end=" ")
# → 2 3 4 5 6 7
# range(start, stop, step) — dengan langkah tertentu
for i in range(0, 20, 5):
print(i, end=" ")
# → 0 5 10 15
# range mundur
for i in range(10, 0, -1):
print(i, end=" ")
# → 10 9 8 7 6 5 4 3 2 1
# ANTI-PATTERN: range() untuk iterasi koleksi yang sudah ada
angka = [10, 20, 30, 40, 50]
for i in range(len(angka)):
print(angka[i])
# BENAR: iterasi langsung
for n in angka:
print(n)
# Kapan range() memang tepat digunakan:
# 1. Mengulang N kali tanpa butuh elemen
for _ in range(3):
kirim_ping()
# 2. Menghasilkan angka dalam rentang tertentu
kuadrat = [i**2 for i in range(1, 11)] # [1, 4, 9, 16, ..., 100]
enumerate() — Indeks dan Nilai Sekaligus
#
Saat kamu memang butuh indeks dan nilainya, gunakan enumerate() — bukan range(len()):
buah = ["apel", "jeruk", "mangga"]
# ANTI-PATTERN: range(len()) hanya untuk mendapat indeks
for i in range(len(buah)):
print(f"{i}: {buah[i]}")
# BENAR: enumerate() memberikan keduanya sekaligus
for i, item in enumerate(buah):
print(f"{i}: {item}")
# → 0: apel
# → 1: jeruk
# → 2: mangga
# Mulai penomoran dari angka lain
for nomor, item in enumerate(buah, start=1):
print(f"{nomor}. {item}")
# → 1. apel
# → 2. jeruk
# → 3. mangga
zip() — Iterasi Beberapa Koleksi Sekaligus
#
zip() menggabungkan dua atau lebih iterable menjadi pasangan (tuple), berguna untuk iterasi paralel:
nama = ["Budi", "Ani", "Citra"]
nilai = [85, 92, 78]
# ANTI-PATTERN: iterasi via indeks untuk dua list
for i in range(len(nama)):
print(f"{nama[i]}: {nilai[i]}")
# BENAR: zip() lebih bersih dan ekspresif
for n, v in zip(nama, nilai):
print(f"{n}: {v}")
# → Budi: 85
# → Ani: 92
# → Citra: 78
# zip dengan tiga koleksi atau lebih
kota = ["Jakarta", "Surabaya", "Bandung"]
for n, v, k in zip(nama, nilai, kota):
print(f"{n} dari {k}: {v}")
# Perilaku zip: berhenti di iterable terpendek
a = [1, 2, 3, 4, 5]
b = ["x", "y", "z"]
print(list(zip(a, b))) # → [(1, 'x'), (2, 'y'), (3, 'z')] — elemen ke-4 dan 5 dibuang
# Gunakan itertools.zip_longest() jika ingin mempertahankan semua elemen
from itertools import zip_longest
print(list(zip_longest(a, b, fillvalue="-")))
# → [(1, 'x'), (2, 'y'), (3, 'z'), (4, '-'), (5, '-')]
while Loop
#
while loop mengeksekusi blok kode selama kondisinya bernilai True. Digunakan saat jumlah iterasi tidak diketahui di awal.
# Pola dasar
hitung = 0
while hitung < 5:
print(hitung)
hitung += 1
# Input loop — terus minta input sampai valid
while True:
jawaban = input("Lanjutkan? (y/n): ").lower()
if jawaban in ("y", "n"):
break
print("Masukkan 'y' atau 'n'")
# Retry dengan batas maksimum
MAX_PERCOBAAN = 3
percobaan = 0
while percobaan < MAX_PERCOBAAN:
berhasil = coba_koneksi()
if berhasil:
break
percobaan += 1
print(f"Gagal, percobaan {percobaan}/{MAX_PERCOBAAN}")
Selalu pastikan ada kondisi yang akan menghentikanwhileloop. Loop tanpa jalan keluar (infinite loop) akan membekukan program. Polawhile Trueaman selama adabreakyang reachable di dalam loop.
break, continue, dan pass
#
break — Hentikan Loop Sepenuhnya
#
# break menghentikan loop dari dalam
angka = [3, 7, 2, 9, 4, 1, 8]
target = 9
for n in angka:
if n == target:
print(f"Ditemukan: {n}")
break # hentikan loop begitu target ditemukan
else:
print("Tidak ditemukan") # dieksekusi hanya jika loop selesai TANPA break
continue — Lewati Iterasi Saat Ini
#
# continue melompati sisa blok dan lanjut ke iterasi berikutnya
for i in range(10):
if i % 2 == 0:
continue # lewati angka genap
print(i, end=" ")
# → 1 3 5 7 9
# Contoh praktis: lewati baris kosong saat membaca file
baris_list = ["Budi", "", "Ani", "", "Citra"]
for baris in baris_list:
if not baris.strip():
continue # lewati baris kosong
proses(baris)
pass — Placeholder Kosong
#
# pass adalah pernyataan yang tidak melakukan apapun
# berguna saat blok kode wajib ada tapi belum diimplementasi
for item in data:
pass # TODO: implementasi nanti
# Atau untuk kelas/fungsi kosong sementara
class DataProcessor:
pass # akan diisi nanti
def hitung_bonus():
pass # placeholder
else pada Loop — Fitur Jarang Diketahui
#
Python memiliki klausa else untuk for dan while yang dieksekusi ketika loop selesai secara normal (tanpa break):
# for...else
def cari_prima(angka_list):
for n in angka_list:
for pembagi in range(2, int(n**0.5) + 1):
if n % pembagi == 0:
break # bukan prima, hentikan loop dalam
else:
# loop dalam selesai tanpa break = tidak ada pembagi = prima
print(f"{n} adalah bilangan prima")
cari_prima([2, 3, 4, 5, 6, 7, 8, 9, 10])
# → 2 adalah bilangan prima
# → 3 adalah bilangan prima
# → 5 adalah bilangan prima
# → 7 adalah bilangan prima
# while...else — praktis untuk pencarian dengan batas percobaan
import time
MAX_RETRY = 5
percobaan = 0
while percobaan < MAX_RETRY:
if coba_koneksi_database():
print("Koneksi berhasil")
break
percobaan += 1
time.sleep(2)
else:
# while selesai tanpa break = semua percobaan gagal
raise ConnectionError(f"Gagal koneksi setelah {MAX_RETRY} percobaan")
List Comprehension #
List comprehension adalah cara ringkas dan Pythonic untuk membuat list baru dari iterasi, sering kali menggantikan loop for yang hanya membangun list:
# ANTI-PATTERN: loop untuk membangun list
kuadrat = []
for i in range(1, 11):
kuadrat.append(i ** 2)
# BENAR: list comprehension — lebih ringkas dan biasanya lebih cepat
kuadrat = [i ** 2 for i in range(1, 11)]
print(kuadrat) # → [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# Dengan kondisi filter
genap = [i for i in range(20) if i % 2 == 0]
print(genap) # → [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# Transformasi string
nama_list = [" budi ", "ANI", "citra"]
bersih = [nama.strip().title() for nama in nama_list]
print(bersih) # → ['Budi', 'Ani', 'Citra']
# Nested comprehension — matriks
matriks = [[i * j for j in range(1, 4)] for i in range(1, 4)]
print(matriks)
# → [[1, 2, 3], [2, 4, 6], [3, 6, 9]]
# Meratakan list bersarang
bersarang = [[1, 2, 3], [4, 5], [6, 7, 8, 9]]
datar = [item for sublist in bersarang for item in sublist]
print(datar) # → [1, 2, 3, 4, 5, 6, 7, 8, 9]
# Dict comprehension
harga = {"apel": 5000, "jeruk": 8000, "mangga": 12000}
# Terapkan diskon 10% ke semua harga
harga_diskon = {nama: int(harga * 0.9) for nama, harga in harga.items()}
print(harga_diskon)
# → {'apel': 4500, 'jeruk': 7200, 'mangga': 10800}
# Set comprehension
angka = [1, 2, 2, 3, 3, 3, 4]
unik_kuadrat = {n ** 2 for n in angka}
print(unik_kuadrat) # → {1, 4, 9, 16}
Generator Expression #
Generator expression mirip list comprehension tapi menggunakan tanda kurung biasa () dan menghasilkan nilai satu per satu secara lazy — tidak membuat seluruh koleksi di memori:
# List comprehension: membuat seluruh list di memori sekaligus
kuadrat_list = [i**2 for i in range(1_000_000)] # ~8MB memori
# Generator expression: hitung satu per satu saat dibutuhkan
kuadrat_gen = (i**2 for i in range(1_000_000)) # hampir 0 memori
# Berguna untuk operasi yang hanya membutuhkan satu lintasan
total = sum(i**2 for i in range(1_000_000)) # efisien, tidak perlu list
ada_negatif = any(n < 0 for n in data) # berhenti di elemen pertama yang negatif
semua_positif = all(n > 0 for n in data) # berhenti di elemen pertama yang tidak positif
Fungsi Iterasi Built-in Penting #
Python menyediakan banyak fungsi built-in yang bekerja dengan iterasi:
angka = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3]
# Agregasi
print(sum(angka)) # → 39
print(min(angka)) # → 1
print(max(angka)) # → 9
print(len(angka)) # → 10
# sorted() — kembalikan list baru yang terurut (tidak ubah asli)
print(sorted(angka)) # → [1, 1, 2, 3, 3, 4, 5, 5, 6, 9]
print(sorted(angka, reverse=True)) # → [9, 6, 5, 5, 4, 3, 3, 2, 1, 1]
# Urutkan berdasarkan kriteria custom
siswa = [("Budi", 85), ("Ani", 92), ("Citra", 78)]
urut_nilai = sorted(siswa, key=lambda s: s[1], reverse=True)
print(urut_nilai) # → [('Ani', 92), ('Budi', 85), ('Citra', 78)]
# filter() — saring elemen yang memenuhi kondisi
positif = list(filter(lambda n: n > 0, [-3, 1, -2, 4, -1, 5]))
print(positif) # → [1, 4, 5]
# map() — transformasi setiap elemen
kuadrat = list(map(lambda n: n**2, [1, 2, 3, 4, 5]))
print(kuadrat) # → [1, 4, 9, 16, 25]
# any() dan all()
print(any(n > 8 for n in angka)) # → True (ada yang > 8)
print(all(n > 0 for n in angka)) # → True (semua > 0)
itertools — Kombinasi Iterasi Lanjutan
#
Modul itertools menyediakan alat iterasi yang powerful dan efisien memori:
from itertools import chain, islice, product, combinations, permutations
# chain — gabungkan beberapa iterable menjadi satu
a = [1, 2, 3]
b = [4, 5, 6]
c = [7, 8, 9]
for n in chain(a, b, c):
print(n, end=" ")
# → 1 2 3 4 5 6 7 8 9
# islice — ambil N elemen pertama dari iterable (lazy)
for n in islice(range(1_000_000), 5):
print(n, end=" ")
# → 0 1 2 3 4
# product — perkalian kartesian (seperti nested for)
for warna, ukuran in product(["merah", "biru"], ["S", "M", "L"]):
print(f"{warna}-{ukuran}", end=" ")
# → merah-S merah-M merah-L biru-S biru-M biru-L
# combinations — kombinasi tanpa pengulangan
for combo in combinations([1, 2, 3, 4], 2):
print(combo, end=" ")
# → (1,2) (1,3) (1,4) (2,3) (2,4) (3,4)
# permutations — semua susunan berbeda
for perm in permutations("ABC", 2):
print("".join(perm), end=" ")
# → AB AC BA BC CA CB
Ringkasan #
- Iterasi langsung, bukan via indeks —
for item in koleksibukanfor i in range(len(koleksi)). Ini lebih bersih, lebih aman, dan lebih cepat.enumerate()untuk mendapat indeks dan nilai sekaligus — menggantikanrange(len())dalam semua kasus.zip()untuk iterasi paralel dua koleksi atau lebih — berhenti di iterable terpendek, gunakanzip_longestjika perlu semua elemen.for...elsedieksekusi saat loop selesai tanpabreak— idiom yang bersih untuk pola “cari dan laporkan jika tidak ditemukan”.- List comprehension menggantikan loop yang hanya membangun list — lebih ringkas dan biasanya lebih cepat. Dict dan set comprehension juga tersedia.
- Generator expression untuk data besar — sama seperti comprehension tapi lazy, hampir tidak menggunakan memori tambahan.
any()danall()dengan generator expression berhenti lebih awal (short-circuit) — efisien untuk pengecekan kondisi pada koleksi besar.itertoolsuntuk pola iterasi lanjutan —chain,islice,product,combinations,permutationsmenghindari kebutuhan loop bersarang yang kompleks.