Materi Tutorial

Iterators & Generators Python

Dalam dunia Python, Iterators dan Generators adalah kunci efisiensi memori. Mereka memungkinkan Anda untuk memproses data dalam jumlah besar (bahkan tak terbatas) tanpa harus memuat semuanya ke dalam RAM sekaligus.

Bayangkan Anda ingin membaca buku tebal. Iterator memungkinkan Anda membaca halaman per halaman (hanya memuat satu halaman ke memori), alih-alih mencoba menghafal buku setebal 1000 halaman sekaligus.

1. Iterators

Iterator adalah objek yang mengandung jumlah nilai yang dapat dihitung. Iterator dapat diiterasi, yang berarti Anda dapat melintasi semua nilai.

Secara teknis, di Python, iterator adalah objek yang mengimplementasikan protokol iterator, yang terdiri dari metode __iter__() dan __next__().

Contoh Membuat Iterator

Mari kita buat iterator sederhana yang mengembalikan angka dari 1 sampai batas tertentu.

class AngkaSaya:
    def __init__(self, batas):
        self.batas = batas
        self.angka = 1

    def __iter__(self):
        return self

    def __next__(self):
        if self.angka <= self.batas:
            x = self.angka
            self.angka += 1
            return x
        else:
            raise StopIteration

kelaskuu = AngkaSaya(3)
iteratorku = iter(kelaskuu)

print(next(iteratorku)) # Output: 1
print(next(iteratorku)) # Output: 2
print(next(iteratorku)) # Output: 3
# print(next(iteratorku)) # Akan error StopIteration

Saat Anda menggunakan loop for, Python secara otomatis menangani __iter__() dan exception StopIteration.

for x in AngkaSaya(3):
    print(x)

2. Generators

Generator adalah cara sederhana untuk membuat iterator. Alih-alih menulis class yang panjang dengan __iter__() dan __next__(), Anda cukup mendefinisikan fungsi biasa dan menggunakan kata kunci yield di mana Anda ingin mengembalikan data.

Setiap kali yield dipanggil, fungsi akan "berhenti sementara" (pause), menyimpan semua variabelnya, dan melanjutkan dari titik tersebut saat dipanggil lagi.

Contoh Generator Sederhana

def generator_angka(batas):
    angka = 1
    while angka <= batas:
        yield angka
        angka += 1

gen = generator_angka(3)
# Generator juga adalah iterator!
print(next(gen)) # 1
print(next(gen)) # 2
print(next(gen)) # 3

Keunggulan Generator: Efisiensi Memori

Bayangkan Anda perlu memproses 1 juta angka.

Menggunakan List (Memakan Memori):

def ambil_list():
    hasil = []
    for i in range(1000000):
        hasil.append(i)
    return hasil

# Ini akan memakan memori sekitar 40MB+ untuk list integer

Menggunakan Generator (Hemat Memori):

def ambil_generator():
    for i in range(1000000):
        yield i

# Ini hampir tidak memakan memori tambahan, karena angka dihasilkan satu per satu saat diminta.

3. Generator Expression

Mirip dengan List Comprehension, tetapi menggunakan tanda kurung biasa (). Ini menghasilkan generator object, bukan list.

# List Comprehension (Membuat list penuh di memori)
kuadrat_list = [x**2 for x in range(10)]
print(kuadrat_list) # [0, 1, 4, ..., 81]

# Generator Expression (Lazy evaluation)
kuadrat_gen = (x**2 for x in range(10))
print(kuadrat_gen) # <generator object ...>

# Untuk melihat isinya, harus diiterasi
for i in kuadrat_gen:
    print(i, end=" ")

4. Studi Kasus: Membaca File Besar

Jika Anda harus memproses file log server berukuran 10GB.

Salah (Jangan lakukan ini):

def baca_file_salah(nama_file):
    file = open(nama_file)
    isi = file.read() # BAHAYA! Akan memuat seluruh 10GB ke RAM.
    return isi.split("\n")

Benar (Gunakan Generator):

def baca_ file_benar(nama_file):
    for baris in open(nama_file):
        yield baris

# Kita bisa loop file 10GB tanpa masalah memori
for baris in baca_file_benar("server.log"):
    if "ERROR" in baris:
        print(baris)

Kesimpulan

Edit tutorial ini