Loop for bekerja otomatis, tetapi otomasi itu kadang membatasi: kadang kita ingin mengambil tepat satu elemen, mengintip dua-dua elemen, atau membagi aliran data ke beberapa proses. Fungsi bawaan iter() dan next() membuka kendali penuh itu — sekaligus memperlihatkan secara persis apa yang terjadi di dalam mesin iterasi yang kita bahas pada Chapter Iterable dan Iterator.

Membuat Iterator dengan iter() #

Fungsi iter() menerima sebuah iterable dan mengembalikan kursor segar yang siap membaca dari elemen pertama. Setiap panggilan next() pada kursor tersebut mengambil satu elemen sekaligus memajukan posisi baca:

python
angka = [10, 20, 30]
iterator = iter(angka)

print(next(iterator))
print(next(iterator))
print(next(iterator))

Output yang Dihasilkan:

text
10
20
30

Bedah prosesnya baris per baris:

  1. Baris 2 (iterator = iter(angka)): interpreter membuat list_iterator baru dengan posisi baca menunjuk sebelum elemen pertama.
  2. Baris 4 (print(next(iterator))): next() mengembalikan elemen 10 dan memajukan posisi baca ke elemen kedua.
  3. Baris 5-6: dua pemanggilan berikutnya mengambil 20 lalu 30; posisi baca kini berada di ujung list.

Satu iterable bisa memiliki lebih dari satu kursor aktif, dan setiap kursor berjalan dengan kecepatannya sendiri. Setiap panggilan iter() selalu memproduksi iterator yang independen:

python
buah = ["apel", "jeruk", "mangga"]
tim_a = iter(buah)
tim_b = iter(buah)

print(next(tim_a))
print(next(tim_b))
print(next(tim_a))

Output yang Dihasilkan:

text
apel
apel
jeruk

Kedua kursor membaca dari list yang sama, tetapi posisinya tercatat terpisah: tim_a sudah dua langkah (apel, jeruk) sementara tim_b baru satu langkah (apel). Inilah sebabnya list bisa diiterasi berulang kali — setiap for membuat kursor barunya sendiri.

Mengambil Elemen dengan next() dan StopIteration #

Apa yang terjadi jika next() dipanggil setelah data habis? Iterator tidak mengembalikan None; iterator mengangkat exception StopIteration:

python
>>> nomor = iter([7, 8])
>>> next(nomor)
7
>>> next(nomor)
8
>>> next(nomor)
Traceback (most recent call last):
    ...
StopIteration

Jika akhir aliran adalah kondisi normal yang kita antisipasi, next() menerima argumen kedua sebagai nilai default — nilai yang dikembalikan sebagai pengganti exception:

python
antrean = iter(["A001", "A002"])

print(next(antrean, "antrean kosong"))
print(next(antrean, "antrean kosong"))
print(next(antrean, "antrean kosong"))

Output yang Dihasilkan:

text
A001
A002
antrean kosong

Dua pemanggilan pertama masih menemukan nomor antrean asli. Pemanggilan ketiga menemukan aliran kosong, sehingga next() mengembalikan string default "antrean kosong" tanpa exception sedikit pun.

Pola nilai default ini cocok untuk loop “tarik sampai habis”: nilai default berperan sebagai penanda bahwa aliran sudah selesai, sehingga loop while bisa berhenti dengan rapi tanpa perlu menangkap StopIteration sama sekali. Pemilihan nilai default harus hati-hati — gunakan nilai yang dipastikan tidak pernah muncul sebagai data asli, misalnya None atau string penanda khusus.

Melihat Jebakan Mutasi List dari Dekat #

Pada Chapter Iterasi Collections kita melihat bahwa menghapus elemen dari list yang sedang diiterasi membuat sebagian elemen terlewat. Sekarang, dengan kursor yang bisa kita maju manual, mekanisme loncatannya terlihat telanjang:

python
angka = [1, 2, 2, 3, 4]
iterator = iter(angka)

print(next(iterator))
print(next(iterator))
angka.remove(2)
print(next(iterator))
print(list(iterator))

Output yang Dihasilkan:

text
1
2
3
[4]

Mari kita lacak setiap langkahnya:

  1. next(iterator) pertama: mengembalikan 1; posisi baca berpindah ke indeks 1.
  2. next(iterator) kedua: mengembalikan 2 pertama; posisi baca berpindah ke indeks 2.
  3. angka.remove(2): list berubah menjadi [1, 2, 3, 4] — angka 2 yang kedua bergeser turun ke indeks 1.
  4. next(iterator) ketiga: kursor membaca indeks 2, yang kini berisi 3. Angka 2 yang bergeser tidak pernah tersentuh — inilah elemen yang “lolos” saat loop for menjalankan skenario yang sama.
  5. list(iterator): sisa aliran hanya [4], menegaskan bahwa satu nilai memang terlewat selamanya.

Dengan protokol iterasi kini dikuasai penuh, dua chapter berikutnya menyediakan alat bantu bawaan yang menghidupkan pola-pola berulang: enumerate() untuk pasangan posisi-nilai dan zip() untuk perjalanan beberapa koleksi sekaligus.