Python & AI Tutorials Logo
Pemrograman Python

36. Generator dan Iterasi Lazy

Di Bab 35, kita mempelajari bagaimana iterasi bekerja di Python melalui iterable dan iterator. Kita melihat bahwa iterator mengembalikan nilai satu per satu saat diminta, yang memungkinkan Python memproses urutan tanpa memuat semuanya ke memori sekaligus. Sekarang kita akan mengeksplorasi generator, cara paling elegan dan praktis di Python untuk membuat iterator.

Generator adalah fungsi (function) yang bisa menjeda dan melanjutkan eksekusinya, menghasilkan nilai satu per satu saat diminta, alih-alih menghitung semua nilai di awal dan menyimpannya di memori. Pendekatan ini—disebut evaluasi malas (lazy evaluation)—berarti nilai hanya dihasilkan ketika dibutuhkan, menjadikannya salah satu fitur Python yang paling kuat untuk menulis kode yang hemat memori.

36.1) Apa Itu Generator dan Kenapa Berguna

36.1.1) Masalah dengan Membuat List Besar

Mari mulai dengan memahami masalah yang diselesaikan generator. Misalnya kamu perlu memproses urutan berisi satu juta angka. Berikut pendekatan tradisional menggunakan list:

python
# Membuat list berisi satu juta kuadrat
def get_squares_list(n):
    """Mengembalikan list kuadrat dari 0 hingga n-1."""
    squares = []
    for i in range(n):
        squares.append(i * i)
    return squares
 
# Ini membuat list dengan 1.000.000 angka di memori
numbers = get_squares_list(1_000_000)
print(f"First five squares: {numbers[:5]}")  # Output: First five squares: [0, 1, 4, 9, 16]

Pendekatan ini punya masalah besar: ia membuat dan menyimpan semua satu juta angka di memori sekaligus, bahkan jika kamu hanya perlu memprosesnya satu per satu. Untuk dataset yang lebih besar atau perhitungan yang lebih kompleks, ini bisa menghabiskan memori dalam jumlah besar atau bahkan membuat program kamu crash.

36.1.2) Memperkenalkan Generator: Menghitung Nilai Saat Dibutuhkan

Sebuah generator adalah tipe khusus dari fungsi yang menghasilkan nilai satu per satu, hanya saat diminta. Alih-alih membangun dan mengembalikan list lengkap, generator menghitung setiap nilai sesuai kebutuhan dan "mengingat" posisi terakhirnya di antara pemanggilan.

Berikut fungsionalitas yang sama diimplementasikan sebagai generator:

python
# Membuat generator kuadrat
def get_squares_generator(n):
    """Menghasilkan kuadrat dari 0 hingga n-1, satu per satu."""
    for i in range(n):
        yield i * i  # yield menjeda fungsi dan mengembalikan sebuah nilai
 
# Ini membuat objek generator, bukan list
squares_gen = get_squares_generator(1_000_000)
print(squares_gen)  # Output: <generator object get_squares_generator at 0x...>
 
# Ambil nilai satu per satu
print(next(squares_gen))  # Output: 0
print(next(squares_gen))  # Output: 1
print(next(squares_gen))  # Output: 4

Generator tidak menghitung semua satu juta kuadrat di awal. Sebaliknya, ia menghitung setiap kuadrat hanya ketika kamu memanggil next() padanya. Di antara pemanggilan, generator "menjeda" dan mengingat state-nya (nilai i saat ini).

36.1.3) Efisiensi Memori: Keunggulan Utama

Perbedaan memori antara list dan generator jadi sangat mencolok untuk dataset besar. Mari bandingkan:

python
import sys
 
# Pendekatan list: menyimpan semua nilai
def squares_list(n):
    return [i * i for i in range(n)]
 
# Pendekatan generator: menghitung nilai saat diminta
def squares_generator(n):
    for i in range(n):
        yield i * i
 
# Bandingkan penggunaan memori untuk 100.000 angka
list_result = squares_list(100_000)
gen_result = squares_generator(100_000)
 
print(f"List size in memory: {sys.getsizeof(list_result):,} bytes")
# Output: List size in memory: 800,984 bytes (actual size may vary)
 
print(f"Generator size in memory: {sys.getsizeof(gen_result)} bytes")
# Output: Generator size in memory: 200 bytes (actual size may vary)

List mengonsumsi lebih dari 800 KB memori, sementara generator hanya memakai 200 byte—terlepas dari berapa banyak nilai yang pada akhirnya akan dihasilkan. Generator hanya menyimpan state fungsi (nilai i saat ini dan titik untuk melanjutkan), bukan urutan nilai yang sebenarnya.

36.1.4) Kapan Generator Berguna

Generator unggul dalam beberapa skenario umum:

Memproses File Besar:

python
def read_large_file(filename):
    """Menghasilkan baris dari file satu per satu."""
    with open(filename, 'r') as file:
        for line in file:
            yield line.strip()
 
# Memproses file log besar tanpa memuat semuanya ke memori
for line in read_large_file('huge_log.txt'):
    if 'ERROR' in line:
        print(line)

Urutan Tak Terbatas:

python
def fibonacci():
    """Menghasilkan angka Fibonacci tanpa batas."""
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b
 
# Menghasilkan angka Fibonacci selamanya (atau sampai kamu berhenti meminta)
fib = fibonacci()
print([next(fib) for _ in range(10)])
# Output: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

36.1.5) Generator Adalah Iterator

Seperti yang kita pelajari di Bab 35, generator sebenarnya adalah jenis khusus dari iterator. Generator otomatis mengimplementasikan protokol iterator (__iter__() dan __next__()), itulah sebabnya mereka bekerja mulus dengan loop for:

python
def countdown(n):
    """Menghasilkan hitung mundur dari n sampai 1."""
    while n > 0:
        yield n
        n -= 1
 
# Generator bekerja langsung di loop for
for num in countdown(5):
    print(num)
# Output:
# 5
# 4
# 3
# 2
# 1

Ketika kamu menggunakan generator di loop for, Python otomatis memanggil next() padanya berulang kali sampai generator habis (memunculkan StopIteration).

36.2) Membuat Fungsi Generator dengan yield

36.2.1) Pernyataan yield: Menjeda dan Melanjutkan

Pernyataan yield adalah yang membuat sebuah fungsi menjadi generator. Ketika Python menjumpai yield, Python melakukan sesuatu yang spesial: alih-alih mengembalikan nilai dan mengakhiri fungsi, Python menjeda fungsi dan mengembalikan nilai tersebut. Lain kali kamu memanggil next() pada generator, eksekusi dilanjutkan tepat setelah pernyataan yield.

Berikut contoh sederhana yang mendemonstrasikan perilaku jeda-dan-lanjut ini:

python
def simple_generator():
    """Mendemonstrasikan bagaimana yield menjeda eksekusi."""
    print("Starting generator")
    yield 1
    print("Resuming after first yield")
    yield 2
    print("Resuming after second yield")
    yield 3
    print("Generator finished")
 
gen = simple_generator()
print("Created generator")
# Output:
# Created generator
 
print(f"First value: {next(gen)}")
# Output:
# Starting generator
# First value: 1
 
print(f"Second value: {next(gen)}")
# Output:
# Resuming after first yield
# Second value: 2
 
print(f"Third value: {next(gen)}")
# Output:
# Resuming after second yield
# Third value: 3
 
try:
    next(gen)
except StopIteration:
    print("Generator exhausted - no more values")
# Output:
# Generator finished
# Generator exhausted - no more values

Perhatikan bagaimana eksekusi fungsi diselingi dengan pemanggilan next(). Setiap yield menjeda fungsi, dan setiap next() melanjutkannya dari tempat terakhir.

36.2.2) State Generator: Mengingat Variabel Lokal

Generator mengingat semua variabel lokalnya di antara yield. Ini membuat generator berguna untuk mempertahankan state di berbagai pemanggilan:

python
def counter(start=0):
    """Menghasilkan angka berurutan mulai dari start."""
    current = start
    while True:
        yield current
        current += 1
 
# Generator mengingat 'current' di antara yield
count = counter(10)
print(next(count))  # Output: 10
print(next(count))  # Output: 11
print(next(count))  # Output: 12
 
# Setiap generator punya state independennya sendiri
count1 = counter(0)
count2 = counter(100)
print(next(count1))  # Output: 0
print(next(count2))  # Output: 100
print(next(count1))  # Output: 1
print(next(count2))  # Output: 101

Variabel current dipertahankan setiap kali generator menjeda pada yield dan dilanjutkan pada pemanggilan next() berikutnya. Ini memungkinkan generator melanjutkan menghitung dari nilai terakhirnya. Setiap instance generator mempertahankan state independennya sendiri.

36.2.3) Melakukan Yield di Dalam Loop: Pola Paling Umum

Penggunaan generator yang paling umum adalah melakukan yield nilai di dalam loop. Pola ini menghasilkan sebuah urutan nilai:

python
def even_numbers(start, end):
    """Menghasilkan angka genap dalam rentang yang diberikan."""
    current = start if start % 2 == 0 else start + 1
    while current <= end:
        yield current
        current += 2
 
# Menggunakan generator
evens = even_numbers(1, 20)
print(list(evens))
# Output: [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

Setiap iterasi loop menghasilkan satu nilai, lalu lanjut ke iterasi berikutnya ketika next() dipanggil lagi.

36.2.4) Banyak Pernyataan Yield

Sebuah generator bisa memiliki beberapa pernyataan yield di titik yang berbeda dalam kodenya. Eksekusi mengalir melaluinya secara berurutan:

python
def process_data(data):
    """Menghasilkan data yang diproses beserta pesan status."""
    yield "Starting processing..."
    
    cleaned = [item.strip().lower() for item in data]
    yield f"Cleaned {len(cleaned)} items"
    
    unique = list(set(cleaned))
    yield f"Found {len(unique)} unique items"
    
    for item in sorted(unique):
        yield item
 
# Memproses beberapa data
data = ["  Apple  ", "Banana", "apple", "Cherry", "BANANA"]
processor = process_data(data)
 
for result in processor:
    print(result)
# Output:
# Starting processing...
# Cleaned 5 items
# Found 3 unique items
# apple
# banana
# cherry

Pola ini berguna untuk generator yang perlu melakukan pekerjaan penyiapan, menghasilkan informasi status, lalu menghasilkan data sebenarnya.

36.3) Ekspresi Generator vs List Comprehension

36.3.1) Memperkenalkan Ekspresi Generator

Di Bab 34, kita mempelajari list comprehension—cara ringkas untuk membuat list. Ekspresi generator (generator expression) memakai sintaks yang hampir identik tetapi membuat generator alih-alih list.

Ekspresi generator pada dasarnya adalah cara ringkas untuk menulis fungsi generator sederhana. Bandingkan dua pendekatan yang setara ini:

python
# Fungsi generator
def squares_function(n):
    for x in range(n):
        yield x * x
 
# Ekspresi generator - melakukan hal yang sama
squares_expression = (x * x for x in range(10))
 
# Keduanya membuat objek generator
gen1 = squares_function(10)
gen2 = squares_expression
 
print(type(gen1))  # Output: <class 'generator'>
print(type(gen2))  # Output: <class 'generator'>
 
# Keduanya menghasilkan nilai yang sama
print(list(squares_function(10)))  # Output: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
print(list(squares_expression))  # Output: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Sintaksnya hampir identik dengan list comprehension. Perbedaannya adalah: gunakan tanda kurung () alih-alih kurung siku [], dan sementara list comprehension membuat list, ekspresi generator membuat generator:

python
# List comprehension - membuat seluruh list di memori
squares_list = [x * x for x in range(10)]
print(squares_list)
# Output: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
 
# Ekspresi generator - membuat objek generator
squares_gen = (x * x for x in range(10))
print(squares_gen)
# Output: <generator object <genexpr> at 0x...>
 
# Konversi ke list untuk melihat nilainya
print(list(squares_gen))
# Output: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Ekspresi generator memberikan sintaks ringkas yang sama seperti list comprehension tetapi dengan efisiensi memori dari generator.

36.3.2) Perbandingan Memori: Saat Ini Penting

Untuk urutan kecil, perbedaan memori antara list comprehension dan ekspresi generator bisa diabaikan. Tetapi untuk urutan besar, perbedaannya menjadi signifikan:

python
import sys
 
# Urutan kecil - perbedaan minimal
small_list = [x for x in range(100)]
small_gen = (x for x in range(100))
 
print(f"Small list: {sys.getsizeof(small_list)} bytes")
# Output: Small list: 920 bytes (actual size may vary)
print(f"Small generator: {sys.getsizeof(small_gen)} bytes")
# Output: Small generator: 192 bytes (actual size may vary)
 
# Urutan besar - perbedaan besar
large_list = [x for x in range(1_000_000)]
large_gen = (x for x in range(1_000_000))
 
print(f"Large list: {sys.getsizeof(large_list):,} bytes")
# Output: Large list: 8,448,728 bytes (actual size may vary)
print(f"Large generator: {sys.getsizeof(large_gen)} bytes")
# Output: Large generator: 192 bytes (actual size may vary)

Ukuran generator tetap konstan terlepas dari berapa banyak nilai yang akan dihasilkannya—ia hanya menyimpan ekspresi dan state saat ini. Namun list harus menyimpan semua nilai di memori, itulah sebabnya ukurannya tumbuh sebanding dengan jumlah elemen.

36.3.3) Ekspresi Generator dalam Pemanggilan Fungsi

Ekspresi generator sangat elegan ketika langsung diteruskan ke fungsi yang mengonsumsi iterable. Kamu bisa menghilangkan tanda kurung ekstra ketika ekspresi generator adalah satu-satunya argumen:

python
# Menghitung jumlah kuadrat tanpa membuat list
total = sum(x * x for x in range(100))  # Note: no extra parentheses needed
print(total)
# Output: 328350
 
# Menemukan nilai maksimum dari nilai yang ditransformasikan
numbers = [1, 2, 3, 4, 5]
max_square = max(x * x for x in numbers)
print(max_square)
# Output: 25
 
# Mengecek apakah ada nilai yang memenuhi kondisi
data = [10, 15, 20, 25, 30]
has_large = any(x > 100 for x in data)
print(has_large)
# Output: False

Pola ini hemat memori dan mudah dibaca. Fungsi seperti sum(), max(), min(), any(), dan all() memproses generator satu nilai pada satu waktu, tanpa pernah membuat list perantara.

36.3.4) Memfilter dengan Ekspresi Generator

Ekspresi generator mendukung logika kondisional yang sama seperti list comprehension:

python
# Memfilter angka genap
numbers = range(20)
evens = (x for x in numbers if x % 2 == 0)
print(list(evens))
# Output: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
 
# Transformasi dan filter
words = ["hello", "world", "python", "programming"]
long_upper = (word.upper() for word in words if len(word) > 5)
print(list(long_upper))
# Output: ['PYTHON', 'PROGRAMMING']

36.3.5) Kapan Ekspresi Generator Tidak Cukup

Ekspresi generator itu ringkas dan elegan, tetapi punya keterbatasan. Gunakan fungsi generator saat kamu membutuhkan:

Logika Kompleks:

python
# Terlalu kompleks untuk sebuah ekspresi generator
def process_log_lines(filename):
    """Memproses file log dengan logika kompleks."""
    with open(filename, 'r') as file:
        for line in file:
            line = line.strip()
            if not line or line.startswith('#'):
                continue  # Lewati baris kosong dan komentar
            
            parts = line.split('|')
            if len(parts) >= 3:
                timestamp, level, message = parts[0], parts[1], parts[2]
                if level in ('ERROR', 'CRITICAL'):
                    yield {
                        'timestamp': timestamp,
                        'level': level,
                        'message': message
                    }

Banyak Yield atau State:

python
# Ekspresi generator tidak bisa mempertahankan state di seluruh iterasi
def running_total(numbers):
    """Menghasilkan total berjalan dari angka."""
    total = 0
    for num in numbers:
        total += num
        yield total
 
numbers = [1, 2, 3, 4, 5]
print(list(running_total(numbers)))
# Output: [1, 3, 6, 10, 15]

Penanganan Error dan Exception:

python
# Ekspresi generator tidak bisa menangani error/exception
def safe_divide(numbers, divisor):
    """Menghasilkan hasil pembagian, sambil menangani error."""
    for num in numbers:
        try:
            yield num / divisor
        except ZeroDivisionError:
            yield float('inf')

36.4) Kapan Menggunakan Generator Alih-alih List

36.4.1) Dataset Besar: Kasus Penggunaan Utama

Alasan paling kuat untuk menggunakan generator adalah ketika bekerja dengan data dalam jumlah besar. Jika kamu memproses jutaan record, generator bisa jadi pembeda antara program yang berjalan mulus dan yang crash.

Pendekatan buruk - Memuat seluruh file ke memori:

python
# JANGAN LAKUKAN INI untuk file besar
def count_errors_bad(filename):
    """Memuat seluruh file ke memori - akan crash untuk file besar."""
    with open(filename, 'r') as file:
        lines = file.readlines()  # Memuat SELURUH file ke memori
    
    error_count = 0
    for line in lines:
        if 'ERROR' in line:
            error_count += 1
    
    return error_count
 
# Jika file berukuran 10 GB, ini mencoba memuat 10 GB ke memori!

Pendekatan bagus - Menggunakan generator:

python
def read_log_lines(filename):
    """Menghasilkan baris dari file log satu per satu."""
    with open(filename, 'r') as file:
        for line in file:
            yield line.strip()
 
def count_errors_good(filename):
    """Menghitung error tanpa memuat seluruh file ke memori."""
    error_count = 0
    for line in read_log_lines(filename):
        if 'ERROR' in line:
            error_count += 1
    
    return error_count
 
# Ini bekerja efisien bahkan dengan file log berukuran gigabyte
# karena hanya menyimpan satu baris di memori pada satu waktu
count = count_errors_good('huge_application.log')
print(f"Found {count} errors")

Pendekatan generator memproses satu baris pada satu waktu, sehingga penggunaan memori tetap konstan terlepas dari ukuran file. File 10 GB menggunakan jumlah memori yang sama seperti file 10 KB.

36.4.2) Urutan Tak Terbatas atau Panjang yang Tidak Diketahui

Generator sangat cocok untuk urutan di mana kamu tidak tahu panjangnya lebih dulu atau di mana urutan tersebut secara konsep tidak terbatas:

python
def user_input_stream():
    """Menghasilkan input pengguna sampai mereka mengetik 'quit'."""
    while True:
        user_input = input("Enter a number (or 'quit'): ")
        if user_input.lower() == 'quit':
            break
        try:
            yield int(user_input)
        except ValueError:
            print("Invalid number, try again")
 
# Memproses input pengguna saat masuk
total = 0
count = 0
for number in user_input_stream():
    total += number
    count += 1
    print(f"Running average: {total / count:.2f}")

Kamu tidak bisa membuat list dengan panjang yang tidak diketahui, tetapi generator menangani ini secara natural.

36.4.3) Transformasi Berantai: Membangun Pipeline Data

Ketika kamu perlu menerapkan banyak transformasi pada data, generator memungkinkan kamu merangkai operasi tanpa membuat list perantara:

python
# Mentransformasikan angka melalui beberapa tahap
def generate_numbers(n):
    """Menghasilkan angka dari 1 sampai n."""
    for i in range(1, n + 1):
        yield i
 
def square_numbers(numbers):
    """Menghasilkan kuadrat dari angka input."""
    for num in numbers:
        yield num * num
 
def keep_even(numbers):
    """Menghasilkan hanya angka genap."""
    for num in numbers:
        if num % 2 == 0:
            yield num
 
# Rangkaikan generator - tidak ada list perantara yang dibuat
numbers = generate_numbers(10)
squared = square_numbers(numbers)
even_squares = keep_even(squared)
 
# Memproses hasil
print(list(even_squares))
# Output: [4, 16, 36, 64, 100]

Setiap tahap memproses satu nilai pada satu waktu, meneruskannya ke tahap berikutnya. Ini hemat memori dan memungkinkan kamu memproses dataset yang lebih besar daripada RAM yang tersedia.

generate_numbers

square_numbers

keep_even

Hasil

Tanpa generator, kamu akan butuh list perantara:

python
# Pendekatan non-generator - membuat list perantara
numbers = list(range(1, 11))           # [1, 2, 3, ..., 10]
squared = [n * n for n in numbers]     # [1, 4, 9, ..., 100]
even_squares = [n for n in squared if n % 2 == 0]  # [4, 16, 36, 64, 100]
 
# Dengan generator - tidak ada list perantara
numbers = (i for i in range(1, 11))
squared = (n * n for n in numbers)
even_squares = (n for n in squared if n % 2 == 0)
print(list(even_squares))
# Output: [4, 16, 36, 64, 100]

Untuk pipeline dengan tiga tahap yang memproses satu juta item, pendekatan list akan membuat tiga list berisi masing-masing satu juta item. Pendekatan generator hanya menyimpan satu nilai di memori pada satu waktu.

36.4.4) Kapan List Lebih Baik daripada Generator

Walaupun punya banyak keunggulan, generator tidak selalu menjadi pilihan yang tepat. Gunakan list ketika kamu membutuhkan:

Iterasi Berkali-kali:

python
# List - bisa diiterasi berkali-kali
numbers = [1, 2, 3, 4, 5]
print(sum(numbers))      # Output: 15
print(max(numbers))      # Output: 5 (works fine)
 
# Generator - hanya bisa diiterasi sekali
numbers_gen = (x for x in range(1, 6))
print(sum(numbers_gen))  # Output: 15
print(max(numbers_gen))  # Output: ValueError: max() iterable argument is empty

Jika kamu perlu memproses data yang sama berkali-kali, gunakan list.

Akses Acak:

python
# Perlu mengakses elemen berdasarkan indeks - gunakan list
students = ['Alice', 'Bob', 'Charlie', 'Diana']
print(students[2])  # Output: Charlie
 
# Generator tidak mendukung indexing
students_gen = (name for name in students)
# students_gen[2]  # ERROR: 'generator' object is not subscriptable

Informasi Panjang:

python
# Perlu mengetahui panjangnya - gunakan list
data = [1, 2, 3, 4, 5]
print(f"Processing {len(data)} items")
 
# Generator tidak punya panjang
data_gen = (x for x in data)
# len(data_gen)  # ERROR: object of type 'generator' has no len()

Dataset Kecil:

python
# Untuk dataset kecil, list tidak masalah dan lebih praktis
small_data = [x * 2 for x in range(10)]
 
# Penghematan memori dari generator tidak signifikan di sini
# dan list lebih fleksibel

36.4.5) Panduan Keputusan Praktis

Berikut panduan praktis untuk memilih antara generator dan list:

Gunakan Generator Saat:

  • Memproses file atau dataset besar
  • Bekerja dengan stream data atau input pengguna
  • Membangun pipeline pemrosesan data
  • Efisiensi memori itu penting
  • Kamu hanya perlu iterasi sekali
  • Urutannya tak terbatas atau sangat panjang

Gunakan List Saat:

  • Dataset kecil (biasanya < 10.000 item)
  • Kamu perlu iterasi berkali-kali
  • Kamu perlu akses acak berdasarkan indeks
  • Kamu perlu mengetahui panjang
  • Kamu perlu meneruskan data ke kode yang mengharapkan list

36.4.6) Mengonversi Antara Generator dan List

Kamu bisa dengan mudah mengonversi antara generator dan list saat diperlukan:

python
# Generator ke list
numbers_gen = (x * 2 for x in range(5))
numbers_list = list(numbers_gen)
print(numbers_list)
# Output: [0, 2, 4, 6, 8]
 
# List ke generator (menggunakan generator expression)
numbers_list = [1, 2, 3, 4, 5]
numbers_gen = (x for x in numbers_list)

Fleksibilitas ini berarti kamu bisa mulai dengan generator untuk efisiensi dan mengonversinya ke list hanya saat kamu memerlukan fitur khusus list:

python
# Mulai dengan generator untuk efisiensi memori
numbers = (x for x in range(1, 1001))
filtered = (x for x in numbers if x % 7 == 0)
 
# Konversi ke list saat kamu butuh iterasi berkali-kali
multiples_of_seven = list(filtered)
 
# Sekarang kamu bisa memakai fitur list
print(f"Count: {len(multiples_of_seven)}")
# Output: Count: 142
 
print(f"First: {multiples_of_seven[0]}")
# Output: First: 7
 
print(f"Last: {multiples_of_seven[-1]}")
# Output: Last: 994
 
# Bisa diiterasi berkali-kali
total = sum(multiples_of_seven)
average = total / len(multiples_of_seven)
print(f"Average: {average:.1f}")
# Output: Average: 500.5

Generator adalah salah satu fitur Python yang paling elegan untuk menulis kode hemat memori. Generator memungkinkan kamu memproses dataset besar, membangun pipeline data, dan bekerja dengan urutan tak terbatas—semuanya sambil menjaga kode tetap bersih dan mudah dibaca. Seiring kamu makin berpengalaman, kamu akan mengembangkan intuisi kapan generator adalah alat yang tepat untuk pekerjaan tersebut.

© 2025. Primesoft Co., Ltd.
support@primesoft.ai