Kursus Python / Memahami iterator, generator, dan yield
Iterator memberikan satu unsur berikutnya setiap kali diminta, sedangkan generator memungkinkan perilaku itu ditulis dengan yield. Nilai dapat dihitung saat diperlukan, tetapi iterator yang habis tidak otomatis memulai lagi dari awal.
Bedakan iterable dengan iterator
List merupakan iterable, yaitu objek yang dapat menyediakan iterator. iter(values) membuat objek yang menyimpan posisi pembacaan terhadap list tersebut. next(iterator) meminta unsur berikutnya dan menaikkan StopIteration jika tidak ada lagi. Loop for menangani sinyal selesai itu agar perulangan berhenti secara normal.
Fungsi yang mempunyai yield menghasilkan objek generator ketika dipanggil. Isi fungsi generator belum dijalankan sampai diminta melanjutkan. Pada setiap yield, nilai diberikan kepada pemanggil dan keadaan lokal dipertahankan untuk kelanjutan berikutnya. Perilaku dasar dijelaskan pada tutorial iterator dan generator Python.
List menyimpan sekumpulan nilai, sedangkan iterator menyimpan keadaan penelusuran. Karena itu, menyimpan iterator ke variabel lain tidak membuat salinan posisi yang independen. Kedua nama dapat merujuk iterator sama, sebagaimana aturan nama dan objek yang dibagi.
Konsumsi jumlah kumulatif secara bertahap
Simpan kode lengkap sebagai generators.py dengan encoding UTF-8. Gunakan Python 3.12 atau lebih baru melalui lingkungan proyek, lalu jalankan python generators.py. Tidak diperlukan paket atau berkas data tambahan.
def running_totals(amounts):
total = 0
for amount in amounts:
total += amount
yield total
values = running_totals([3500, 8000, 2500])
print(next(values))
print(list(values))
print(list(values))
print(list(running_totals([3500, 8000, 2500])))
Keluaran yang diharapkan:
3500
[11500, 14000]
[]
[3500, 11500, 14000]
next(values) menghasilkan jumlah pertama 3500 dan menghentikan sementara generator. list(values) berikutnya mengumpulkan sisa nilai 11500 dan 14000, bukan mengulangi nilai pertama. Setelah itu, generator sudah habis, sehingga konversi list kedua menghasilkan list kosong.
Baris terakhir memanggil running_totals lagi untuk membuat generator baru. Karena objek ini belum dikonsumsi, seluruh jumlah kumulatif tersedia. Membuat ulang generator berbeda dari mengubah nama variabel yang menunjuk generator lama.
Generator menghindari penyimpanan seluruh hasil sebelum diminta, tetapi input contoh sudah berupa list dan masih membutuhkan memorinya. Memanggil list(generator) juga menyimpan semua hasil yang dikumpulkan. Lazy evaluation mengubah waktu perhitungan dan penyimpanan, bukan menjamin semua program lebih cepat atau memakai memori konstan secara keseluruhan.
Amati posisi iterator dan ekspresi generator
Simpan program kedua sebagai iterator.py dan jalankan python iterator.py. Program ini berdiri sendiri dan memperlihatkan bahwa list sumber tetap ada setelah iteratornya dikonsumsi.
values = [1, 2, 3]
iterator = iter(values)
print(next(iterator))
print(list(iterator))
print(list(iterator))
print(list(values))
expression = (n * 2 for n in values)
print(list(expression))
Keluaran yang diharapkan:
1
[2, 3]
[]
[1, 2, 3]
[2, 4, 6]
Iterator pertama mengeluarkan 1, kemudian list sisanya berisi 2 dan 3. Konsumsi ulang tidak menghasilkan unsur lagi, tetapi list(values) tetap menyalin tiga nilai sumber. List sumber dan posisi iterator merupakan dua hal berbeda.
Bentuk (n * 2 for n in values) merupakan ekspresi generator. Ia menghitung hasil setiap kali dikonsumsi, lalu dapat habis seperti generator fungsi. Bentuk ini berbeda dari list comprehension yang langsung mengumpulkan hasil ke list.
Jika hasil kecil perlu dibaca berkali-kali, menyimpannya sebagai list dapat lebih sederhana. Jika input merupakan aliran yang hanya dapat dibaca sekali, membuat generator baru belum tentu dapat memulihkan input yang sudah dikonsumsi. Tentukan apakah program dapat membuka ulang sumber atau perlu menyimpan hasil.
Tangani kesalahan tertunda dan umur sumber daya
Kesalahan di dalam badan generator dapat terjadi saat konsumsi, bukan saat objek generator dibuat. Misalnya, pada input [3500, "bad"], generator dapat dibuat dan menghasilkan 3500 terlebih dahulu; permintaan berikutnya gagal ketika mencoba menjumlahkan string. Pengujian hanya pada pembuatan generator belum membuktikan seluruh alirannya valid.
- Tambahkan satu
next(values)lagi sebelum pengumpulan list pada program pertama. Dua nilai pertama kini dicetak sendiri dan sisa list hanya berisi 14000. - Ganti input menjadi list kosong pada percobaan terpisah. Permintaan
nextpertama langsung menaikkanStopIteration, sedangkan mengumpulkan generator kosong langsung denganlistmenghasilkan list kosong. - Pulihkan input asli dan buat generator baru untuk pembacaan ulang. Cocokkan bahwa generator habis tetap kosong tetapi generator baru mempunyai seluruh hasil.
- Pulihkan kedua program ke sumber awal dan cocokkan keluaran lengkapnya.
Jika generator membuka berkas, pikirkan apa yang terjadi ketika pemanggil berhenti sebelum semua unsur dibaca. break pada loop saja bukan perintah umum untuk menutup setiap generator yang masih dirujuk. Struktur pemanggil yang mengendalikan with, atau penutupan eksplisit yang dirancang dengan benar, dapat membuat umur sumber daya lebih jelas.
Aturan penutupan berkas dan pembacaan per baris tetap berlaku saat iterator digunakan untuk memproses data. Hindari bergantung pada waktu pengumpulan sampah sebagai satu-satunya mekanisme untuk melepaskan sumber daya yang penting.




