Generator di Python

Generator di Python

Artikel ini menjelaskan tentang generator di Python.

YouTube Video

Generator di Python

Ikhtisar

Generator di Python adalah jenis iterator dan fitur yang kuat untuk melakukan proses berulang secara efisien. Mereka memungkinkan Anda menulis kode yang efisien dalam penggunaan memori saat menangani data dalam jumlah besar.

Apa itu Generator?

Generator di Python adalah fungsi khusus yang menghasilkan satu nilai setiap kali dijalankan, yang didefinisikan menggunakan kata kunci yield. Ciri utamanya adalah dapat menghentikan eksekusi sementara dengan mempertahankan keadaan dan melanjutkan di lain waktu.

Dasar-dasar yield

yield adalah kata kunci yang mengembalikan nilai dan menunda eksekusi fungsi pada saat yang bersamaan.

 1def simple_generator():
 2    yield 1
 3    yield 2
 4    yield 3
 5
 6gen = simple_generator()
 7
 8print(next(gen))  # 1
 9print(next(gen))  # 2
10print(next(gen))  # 3
  • Ketika dipanggil, fungsi ini mengembalikan objek generator yang menghasilkan nilai satu per satu.
  • Jika Anda memanggil next() saat tidak ada nilai berikutnya, akan terjadi error StopIteration.

next() dan StopIteration

 1def simple_generator():
 2    yield 1
 3    yield 2
 4    yield 3
 5
 6gen = simple_generator()
 7
 8try:
 9    while True:
10        value = next(gen)
11        print(value)
12except StopIteration:
13    print("Finished")
  • Dengan secara eksplisit menangani error StopIteration seperti ini, Anda dapat mendeteksi kapan generator telah selesai.

send(value)

send(value) dipanggil untuk melanjutkan generator dan mengirimkan value ke posisi ekspresi yield. Nilai yang dikirim dapat diterima di sisi generator sebagai nilai kembali dari ekspresi yield. Pada pemanggilan pertama, Anda tidak dapat mengirim apa pun selain None dengan send(value), jadi Anda harus menggunakan next() atau send(None).

 1def gen():
 2    x = yield 1
 3    print(f"x = {x}")
 4    y = yield 2
 5    print(f"y = {y}")
 6
 7g = gen()
 8print(next(g))       # -> 1 (value from yield 1)
 9print(g.send(10))    # -> x = 10, 2 (value from yield 2)
10print(g.send(20))    # -> y = 20, StopIteration occurs
  • Dengan send(10), yield pada generator menjadi ekspresi yang mengembalikan 10, dan 10 diberikan ke x.

throw()

Memanggil throw akan melanjutkan generator dan memunculkan exception pada posisi yield yang sedang dijeda. Anda dapat menangani exception di dalam generator untuk melanjutkan pemrosesan. Jika exception tidak ditangkap, maka akan diteruskan ke luar dan generator berakhir.

 1def gen():
 2    try:
 3        yield 1
 4    except ValueError as e:
 5        print(f"Caught: {e}")
 6        yield "recovered"
 7
 8g = gen()
 9print(next(g))   # -> 1
10print(g.throw(ValueError("boom")))  # -> Caught: boom, "recovered"
  • Dalam kode ini, throw dipanggil untuk menyisipkan exception ke dalam generator. Di sisi generator, exception ditangani dan recovered dikembalikan.

close()

Memanggil close() akan mengakhiri generator. Di dalam generator, Anda dapat melakukan pembersihan menggunakan finally. Memanggil next() atau send() setelah close() akan memunculkan error StopIteration.

1def gen():
2    try:
3        yield 1
4    finally:
5        print("Cleaning up...")
6
7g = gen()
8print(next(g))  # -> 1
9g.close()       # -> Cleaning up...
  • Kode ini menunjukkan bahwa memanggil close() mengakhiri generator dan memicu proses pembersihan di dalam finally.

yield from

yield from adalah sintaks yang digunakan untuk mendelegasikan ke subgenerator. Ini adalah cara sederhana untuk memanggil generator lain di dalam generator dan meneruskan semua nilainya ke lingkup luar.

1def sub_gen():
2    yield 1
3    yield 2
4
5def main_gen():
6    yield from sub_gen()
7    yield 3
8
9print(list(main_gen()))  # -> [1, 2, 3]
  • Kode ini mendelegasikan semua nilai dari subgenerator ke generator luar menggunakan yield from, lalu menghasilkan 3.

Hubungan dengan Iterator

Generator secara internal mengimplementasikan __iter__() dan __next__(), sehingga merupakan jenis iterator. Oleh karena itu, mereka sepenuhnya kompatibel dengan operasi yang dapat diiterasi seperti perulangan for.

Integrasi dengan Perulangan for

Di Python, sebuah perulangan for secara internal menggunakan next() untuk mengambil nilai secara otomatis.

1def simple_generator():
2    yield 1
3    yield 2
4    yield 3
5
6for value in simple_generator():
7    print(value)

Dengan metode ini, penanganan StopIteration juga dilakukan secara otomatis.

Membuat Generator Tak Terbatas

1def count_up(start=0):
2    while True:
3        yield start
4        start += 1
5
6counter = count_up()
7print(next(counter))  # 0
8print(next(counter))  # 1

Anda dapat membuat perulangan tak terbatas, namun harus berhati-hati saat menggunakannya.

Ekspresi Generator

Ekspresi generator, yang ditulis menggunakan tanda kurung, memungkinkan Anda mendefinisikan generator dengan sintaks yang mirip dengan list comprehension.

1# List comprehension (generates the entire list at once)
2squares_list = [x**2 for x in range(5)]
3print(squares_list)
4
5# Generator expression
6squares_gen = (x**2 for x in range(5))
7for square in squares_gen:
8    print(square)

Berbeda dengan list comprehension, ekspresi generator tidak memuat semua elemen sekaligus ke dalam memori, sehingga lebih efisien dalam penggunaan memori.

Penanganan Error pada Generator

Exception dapat terjadi di dalam generator. Dalam kasus seperti itu, Anda dapat menggunakan try-except seperti pada kode Python biasa.

 1def safe_divide_generator(numbers, divisor):
 2    """Yields results of dividing numbers by a given divisor safely."""
 3    for number in numbers:
 4        try:
 5            yield number / divisor  # Attempt to divide and yield result.
 6        except ZeroDivisionError:
 7            yield float('inf')  # Return infinity if division by zero occurs.
 8
 9# Example usage
10numbers = [10, 20, 30]
11gen = safe_divide_generator(numbers, 0)  # Create generator with divisor as 0.
12for value in gen:
13    print(value)  # Output: inf, inf, inf

Dalam contoh ini, penanganan error dilakukan dengan benar jika terjadi pembagian dengan nol.

Stack Trace dari Generator

Jika terjadi exception di dalam generator, exception tersebut akan dimunculkan saat generator dilanjutkan kembali.

 1def error_generator():
 2    """A generator that yields values and raises an error."""
 3    yield 1
 4    raise ValueError("An error occurred")  # Raise a ValueError intentionally.
 5    yield 2
 6
 7gen = error_generator()
 8print(next(gen))       # Output: 1 (first value yielded)
 9try:
10    print(next(gen))   # Attempt to get the next value, which raises an error
11except ValueError as e:
12    print(e)           # Output: An error occurred (exception message is printed)
  • Generator ini mengembalikan 1 terlebih dahulu. Error yang terjadi saat dilanjutkan kembali akan ditangkap dan ditampilkan sebagai pesan error.

Contoh Penggunaan Generator

Membaca file baris demi baris (cocok untuk file berukuran besar)

1def read_large_file(filepath):
2    with open(filepath, 'r') as f:
3        for line in f:
4            yield line.strip()
  • Fungsi ini membaca file teks baris demi baris menggunakan iterator, memotong spasi di setiap baris, dan mengembalikannya sebagai generator, memungkinkan file besar diproses dengan penggunaan memori yang rendah.

Generator untuk Deret Fibonacci

1def fibonacci(limit):
2    a, b = 0, 1
3    while a < limit:
4        yield a
5        a, b = b, a + b
6
7for n in fibonacci(100):
8    print(n)
  • Kode ini menggunakan generator untuk menghasilkan bilangan Fibonacci secara berurutan yang kurang dari batas atas dan menampilkannya menggunakan loop for.

Kasus Penggunaan

Generator juga dapat digunakan dalam skenario berikut.

  • Pemrosesan berurutan file CSV atau log berukuran besar
  • Paginasi API
  • Memproses data streaming (misal, Kafka, perangkat IoT)

Ringkasan

Konsep Poin Utama
yield Menunda lalu mengembalikan nilai
Fungsi Generator Fungsi yang berisi yield dan mengembalikan iterator saat dipanggil
Keunggulan Efisien dalam penggunaan memori dan ideal untuk pemrosesan data besar
Ekspresi Generator Memungkinkan sintaks yang ringkas seperti (x for x in iterable)

Dengan menggunakan generator, Anda dapat memproses kumpulan data besar secara efisien sambil menghemat memori dan menjaga agar kode tetap ringkas.

Anda dapat mengikuti artikel di atas menggunakan Visual Studio Code di saluran YouTube kami. Silakan periksa juga saluran YouTube kami.

YouTube Video