Generators & yield — Python

Generators & yield Generator adalah fungsi spesial yang menghasilkan nilai satu per satu saat diminta, alih-alih menghitung semuanya sekaligus dan…

Generator adalah fungsi yang menghasilkan nilai satu per satu, hanya saat diminta, bukan menyiapkan semuanya sekaligus. Bayangin dapur Warung Kopi Pak Darto. Cara pertama: semua pesanan dimasak di awal, lalu dijajarkan di meja. Mejanya penuh, dan pelanggan pertama ikut menunggu semuanya matang. Cara kedua: koki memasak satu pesanan tiap kali pelayan memanggil "berikutnya!", lalu diam menunggu panggilan berikutnya. Fungsi biasa yang mengembalikan list itu cara pertama. Generator itu cara kedua.

🧪 Tebakan cepat: generator masak mencetak masak kopi susu sebelum menyerahkan tiap menu. Programnya menulis dapur = masak(...), lalu print("dapur siap"). Baris pertama yang tercetak masak kopi susu atau dapur siap? Tebak dulu, jawabannya ada di bagian "yield: berhenti sebentar".

yield: berhenti sebentar

def masak(pesanan):
    for menu in pesanan:
        print("masak", menu)
        yield menu

dapur = masak(["kopi susu", "teh manis", "roti bakar"])
print("dapur siap")
print(next(dapur))
print(next(dapur))
dapur siap
masak kopi susu
kopi susu
masak teh manis
teh manis
Panggilan Yang jalan di dalam masak Hasilnya
masak([...]) belum ada objek generator
next(dapur) ke-1 cetak masak kopi susu, berhenti di yield kopi susu
next(dapur) ke-2 lanjut ke putaran kedua, berhenti di yield teh manis
next(dapur) ke-3 putaran ketiga, berhenti di yield roti bakar
next(dapur) ke-4 loop habis, fungsi selesai StopIteration

Habis: StopIteration

Tambahkan dua baris print(next(dapur)) lagi di bawah program tadi. Yang ketiga masih dapat roti bakar, tapi yang keempat gak punya nilai lagi:

dapur siap
masak kopi susu
kopi susu
masak teh manis
teh manis
masak roti bakar
roti bakar
Traceback (most recent call last):
  File "/home/darto/warung.py", line 11, in <module>
    print(next(dapur))
          ~~~~^^^^^^^
StopIteration

StopIteration artinya generator sudah selesai: gak ada yield lagi yang bisa dicapai.

Dipakai di for, dan cuma sekali

dapur = masak(["kopi susu", "teh manis", "roti bakar"])
for menu in dapur:
    print("antar", menu)
print("putaran kedua:")
for menu in dapur:
    print("antar", menu)
print("selesai")
masak kopi susu
antar kopi susu
masak teh manis
antar teh manis
masak roti bakar
antar roti bakar
putaran kedua:
selesai

Deret Fibonacci: menggeser dua angka

Di deret Fibonacci, tiap angka adalah jumlah dua angka sebelumnya: 0, 1, 1, 2, 3, 5, 8, 13, dan seterusnya. Cukup dua variabel, a dan b, yang digeser tiap putaran dengan unpacking dari pelajaran tuple:

a, b = 0, 1
for _ in range(5):
    print(a, b)
    a, b = b, a + b
Putaran a b Sesudah a, b = b, a + b
1 0 1 a = 1, b = 0 + 1 = 1
2 1 1 a = 1, b = 1 + 1 = 2
3 1 2 a = 2, b = 1 + 2 = 3
4 2 3 a = 3, b = 2 + 3 = 5
5 3 5 a = 5, b = 3 + 5 = 8

Generator expression

Mirip list comprehension, tapi pakai kurung biasa:

harga = [15000, 5000, 12000]
naik = (h + 2000 for h in harga)
print(next(naik))   # 17000
print(sum(naik))    # 21000

Bedanya terasa di data besar. Di Python 3.13, 64-bit:

import sys
daftar = [x ** 2 for x in range(10_000_000)]
gen = (x ** 2 for x in range(10_000_000))
print(sys.getsizeof(daftar))   # 89095160
print(sys.getsizeof(gen))      # 200

List-nya butuh sekitar 89 MB, generatornya 200 byte, berapa pun panjang deretnya. Garis bawah di 10_000_000 cuma pemisah ribuan supaya angkanya gampang dibaca.

⚠️ Jebakan yang sering ketemu

TL;DR: Fungsi yang berisi yield adalah generator: memanggilnya cuma membuat objek generator tanpa menjalankan isinya. next() menjalankannya sampai yield berikutnya, menyerahkan nilainya, lalu berhenti di situ; kalau gak ada yield lagi, keluar StopIteration. for memanggil next() untukmu dan berhenti diam-diam. Generator lazy dan cuma bisa dipakai sekali. Generator expression (x * 2 for x in ...) lazy dan hemat memori, sedangkan [...], {...}, dan list(map(...)) eager. Deret Fibonacci digeser dengan a, b = b, a + b.

Yang akan kamu pelajari