Generator

Pada artikel ini, kita akan berguru cara Membuat iterasi memakai generator, apa perbedaan generator dengan iterator dan fungsi, dan mengapa kita harus memakai generator.



 



Tabel Konten









Pengertian Generator



Ada banyak hal yang berlebihan (overhead) di dalam Membuat iterator di Python. Pertama, kita harus Membuat kelas yang memakai metode __iter__() dan __next__() . Kemudian kita juga harus menjaga state dari item, dan harus membangkitkan StopIteration pada dikala tidak ada lagi item yang tersedia.



Hal ini agak panjang dan rumit. Dalam hal ini, untuk menghindari hal tersebut, kita sanggup memakai generator.



Generator di Python ialah cara sederhana Membuat iterator. Semua overhead yang kita sebutkan di atas, akan ditangani secara otomatis oleh generator.



Singkatnya, generator ialah fungsi yang mengembalikan sebuah objek iterator yang padanya sanggup kita lakukan iterasi (satu nilai per satu waktu).







Cara Membuat Generator di Python



Cukup simpel untuk Membuat generator di Python. Mirip dengan Membuat fungsi biasa. Hanya saja, kita menggantikan pernyataan return dengan yield.



Fungsi yang memiliki minimal satu yield (fungsi sanggup berisi lebih dari satu yield atau return), akan menjadi fungsi generator. yield maupun return sama – sama berfungsi mengembalikan suatu nilai dari sebuah fungsi.



Perbedaan return dan yield adalah, return akan menghentikan (terminasi) fungsi secara keseluruhan, sementara yield hanya akan menghentikan sementara (pause) fungsi dan menyimpan semua state variabel yang di dalamnya untuk nantinya sanggup dilanjutkan kembali dari state tersebut.







Perbedaan Fungsi Generator dan Fungsi Biasa



Berikut ialah perbedaan fungsi generator dengan fungsi biasa:




  • Fungsi generator berisi satu atau lebih pernyataan yield


  • Pada dikala dipanggil, fungsi generator akan mengembalikan objek iterator, tapi tidak langsung dieksekusi.


  • Metode __iter__() dan __next__() sudah diimplementasikan secara otomatis. Jadi kita sanggup langsung melakukan iterasi dengan fungsi next().


  • Sekali fungsi menemui yield, fungsi akan pause dan kendali ditransfer kembali ke pemanggil.


  • Variabel lokal dan state-nya diingat untuk pemanggilan selanjutnya.


  • Terakhir, pada dikala fungsi diterminasi (dihentikan total), StopIteration dipanggil secara otomatis.



Berikut ialah pola generator dengan beberapa pernyataan yield




# Fungsi generator sederhana
def my_gen():
n = 1
print('This is printed first')
# Fungsi generator berisi pernyataan yield
yield n


n += 1
print('This is printed second')
yield n


n += 1
print('This is printed at last')
yield n


Selanjutnya, jadinya sanggup dijalankan pada mode interaktif mirip berikut:



>>> # my_gen() mengembalikan objek iterator, tapi tidak langsung mengeksekusinya
>>> a = my_gen()

>>> # Kita sanggup melakukan iterasi pertama memakai next()
>>> next(a)
This is printed first
1
>>> # Sekali fungsi menemukan yield, fungsi akan dipause
>>> # dan kendali dikembalikan ke pemanggil
>>> # Variabel lokal dan state-nya akan diingat untuk pemanggilan selanjutnya
>>> next(a)
This is printed second
2

>>> next(a)
This is printed at last
3

>>> Terakhir, fungsi diterminasi, StopIterasi otomatis dibangkitkan
>>> next(a)
Traceback (most recent call last):
...
StopIteration


Salah satu hal yang perlu diperhatikan untuk pola di atas adalah, nilai dari variabel n tetap diingat pada tiap pemanggilan fungsi.



Berbeda dengan fungsi normal, variabel lokal tidak akan dihancurkan pada dikala pernyataan yield. Selain itu, objek generator hanya sanggup diiterasi untuk sekali saja. Untuk mengulang kembali proses, kita harus Membuat generator lain memakai pernyataan mirip misalnya a = my_gen().



Kita juga sanggup memakai generator di dalam loop for secara langsung. Hal ini lantaran ialah loop for memakai iterator dan melakukan iterasi padanya memakai fungsi next(). StopIteration otomatis dilakukan pada final iterasi.




# Fungsi generator sederhana
def my_gen():
n = 1
print('This is printed first')


# Fungsi generator berisi pernyataan yield
yield n


n += 1
print('This is printed second')
yield n


n += 1
print('This is printed at last')
yield n


# Menggunakan loop for
for item in my_gen():
print(item)


Pada dikala pola di atas dijalankan, jadinya akan tampak mirip berikut:



This is printed first
1
This is printed second
2
This is printed at last
3






Generator Menggunakan Loop



Contoh-contoh di atas jarang dipakai. Kita mempelajarinya hanya untuk tahu teknisnya apa yang bahwasanya terjadi pada generator.



Umumnya, fungsi generator diterapkan pada loop yang memiliki kondisi terminasi (penghentian) yang sesuai.



Mari kita buat pola generator yang berfungsi membalikkan sebuah string.



 
def rev_str(my_str):
length = len(my_str)
for i in range(length - 1,-1,-1):
yield my_str[i]


# Loop for untuk membalikkan string
# Output:
# o
# l
# l
# e
# h


for char in rev_str("hello"):
print(char)


Pada pola di atas, kita memakai fungsi range() untuk menerima indeks secara terbalik yang digunakan dalam loop for.



Fungsi generator mirip itu tidak hanya berlaku untuk string, tapi juga untuk iterable lainnya mirip list, tuple, dan lain – lain.







Generator Expression



Generator sederhana sanggup dibuat dengan memakai generator expression. Dengan generator expression ini, pembuatan generator menjadi mudah.



Mirip dengan fungsi lambda yang Membuat fungsi anonim, generator expression juga Membuat sebuah fungsi generator anonim.



Sintaks dari generator expression mirip dengan list comprehension. Hanya saja tanda kurung [ ] digantikan dengan tanda kurung ( ).



Perbedaan utama antara list comprehension dengan generator expression adalah, list comprehension langsung menghasilkan keseluruhan anggota list, sedangkan generator expression menghasilkannya satu item per satu waktu.



Tipe mirip generator expression ini sering disebut tipe lazy (malas), lantaran ialah hanya memproduksi item pada dikala diminta. Hal inilah yang menjadikan generator expression lebih hemat memori ketimbang list comprehension.




# Membuat list
my_list = [1, 3, 6, 10]


# Tanda [ ] untuk list comprehension
# Output: [1, 9, 36, 100]
[x**2 for x in my_list]


# Hal yang sama sanggup memakai generator expression
# Output: generator object genexpr at 0x0000000002EBDAF8
(x**2 for x in my_list)


Kita sanggup lihat di atas, bahwa generator expression tidak langsung memproduksi hasil secara keseluruhan. Generator expression ini hanya mengembalikan item jikalau diminta.




# Membuat list
my_list = [1, 3, 6, 10]


a = (x**2 for x in my_list)


# Output: 1
print(next(a))


# Output: 9
print(next(a))


# Output: 36
print(next(a))


# Output: 100
print(next(a))


# Output: StopIteration
next(a)


Generator expression juga sanggup digunakan sebagai argumen fungsi. Bila demikian, tanda kurungnya sanggup dihilangkan. Misalnya pada fungsi sum() dan max() mirip berikut:



>>> my_list = [1, 3, 6, 10]
>>> sum(x**2 for x in my_list)
146
>>> max(x**2 for x in my_list)
100






Alasan Penggunaan Generator



Ada beberapa hal yang menjadi alasan penggunaan generator, yaitu sebagai berikut:



1. Mudah diterapkan



Generator sanggup diterapkan dengan lebih simpel dan ringkas dibandingkan dengan kelas iterator. Berikut ini pola penggunaan kelas iterator untuk menghasilkan deret bilangan pangkat 2 dari 0 sampai yang bilangan ditentukan.



class PowTwo:
def __init__(self, max=0):
self.max = max

def __iter__(self):
self.n = 0
return self

def __next__(self):
if self.n > self.max:
raise StopIteration

result = 2 ** self.n
self.n += 1
return result


Dan berikut jadinya sama dengan memakai fungsi generator.



def PowTwoGen(max = 0):
n = 0
while n < max:
yield 2 ** n
n += 1


Dari pola di atas, terlihat bahwa penggunaan generator lebih simpel dan ringkas dibandingkan iterator.



2. Lebih Hemat Memori



Fungsi biasa yang dibuat untuk menghasilkan sequence, akan menyimpan keseluruhan sequence sebelum mengembalikan hasilnya. Hal ini akan menghabiskan memori jikalau jumlah itemnya sangat besar.



Sementara itu, generator jauh lebih hemat memori lantaran ialah hanya memproduksi item satu persatu yaitu hanya dikala dipanggil.



3. Merepresentasikan Stream Tak Berhingga (Infinite Stream)



Generator ialah cara yang paling anggun untuk mewakili fatwa data yang tak berhingga. Stream (aliran) data yang tak berhingga, tidak sanggup disimpan dalam memori, sehingga cocok memakai generator.



Berikut ialah pola untuk membangkitkan semua bilangan genap yang ada (setidaknya secara teoritis saja)



def all_even():
n = 0
while True:
yield n
n += 2


4. Pipelining Generator



Pipeline ialah menjadikan input dari sebuah proses menjadi proses dari operasi yang lain. Generator sanggup digunakan untuk pipeline dari serangkaian operasi. Hal ini akan lebih jelas jikalau diilustrasikan dengan contoh.



Anggaplah kita memiliki sebuah file log dari rantai makanan cepat saji terkenal. File log ini memiliki sebuah kolom (kolom ke-4) yang mencatat jumlah pizza yang terjual setiap jam dan kita ingin menjumlahkannya untuk menerima jumlah pizza yang terjual dalam 5 tahun.



Kita asumsikan bahwa semua yang kosong di kolom ke 4 sebagai 'N/A'. Maka, generator yang sanggup diterapkan untuk hal ini ialah mirip berikut.



with open('penjualan.log') as file:
pizza_col = (line[3] for line in file)
per_jam = (int(x) for x in pizza_col if x != 'N/A')
print("Total pizza terjual = ", sum(per_jam))


Pipelining menjadikan arahan menjadi lebih efisien dan simpel dibaca.



 



Popular posts from this blog

Subitems Listview Berwarna Selang Seling

Source Code Aplikasi Tagihan Internet Memakai Php