Generator
Pada artikel ini, kita akan belajar langkah membuat iterasi memakai generator, apakah bedanya generator dengan iterator dan peranan, dan kenapa kita harus memakai generator.
Pengertian Generator
Ada beberapa hal yang terlalu berlebih (overhead) di saat membuat iterator di Python. Pertama, kita harus membuat kelas yang memakai sistem __iter__() dan __next__(). Selanjutnya kita harus juga jaga state dari poin, dan harus menghidupkan StopIteration di saat tidak lagi ada poin yang ada.
Ini cukup panjang dan sulit. Dalam masalah ini, untuk menghindar hal itu, kita dapat memakai generator. Generator di Python ialah langkah simpel membuat iterator. Semua overhead yang kita sebut di atas, akan diatasi secara automatis oleh generator. Secara singkat, generator ialah peranan yang kembalikan sebuah object iterator yang kepadanya dapat kita kerjakan iterasi (satu nilai per satu waktu).
Cara Membuat Generator di Python
Cukup mudah untuk membikin generator di Python. Serupa dengan membuat peranan biasa. Namun, kita gantikan pengakuan return dengan yield. Peranan yang mempunyai minimum satu yield (peranan dapat berisi lebih satu yield atau return), bisa menjadi peranan generator. yield atau return sama - sama berperan kembalikan satu nilai dari sebuah peranan.
Ketidaksamaan return dan yield ialah, return akan hentikan (terminasi) peranan keseluruhannya, sementara yield cuman akan hentikan sementara (pause) peranan dan simpan semua state faktor yang untuk nanti dapat diteruskan datang dari state itu.
Perbedaan Fungsi Generator dan Fungsi Biasa
Berikut adalah perbedaan fungsi generator dengan fungsi biasa:
Peranan generator berisi satu ataupun lebih pengakuan yield
Di saat diundang, peranan generator akan kembalikan object iterator, tetapi tidak langsung dilakukan.
Sistem __iter__() dan __next__() telah diterapkan secara automatis . Maka kita langsung bisa lakukan iterasi dengan peranan next().
Sekali peranan menjumpai yield, peranan akan pause dan kendalian ditransfer kembali lagi ke pemanggil.
Faktor lokal dan state-nya dikenang untuk panggilan seterusnya.
Paling akhir, di saat peranan diterminasi (disetop total), StopIteration diundang secara automatis.
Berikut adalah contoh generator dengan beberapa pernyataan yield
script.py
IPython Shell
Powered by DataCamp
Seterusnya, hasilnya dapat digerakkan pada model interaktif sebagai berikut:
>>> # my_gen() kembalikan object iterator, tetapi tidak langsung menyelesaikannya
>>> a = my_gen()
>>> # Kita dapat lakukan iterasi pertama memakai next()
>>> next(a)
This is printed first
1
>>> # Sekali peranan mendapati yield, peranan akan dipause
>>> # dan kendalian dibalikkan ke pemanggil
>>> # Faktor lokal dan state-nya akan dikenang untuk panggilan seterusnya
>>> next(a)
This is printed second
2
>>> next(a)
This is printed at last
3
>>> Paling akhir, peranan diterminasi, StopIterasi automatis dibangkitkan
>>> next(a)
Traceback (most recent call last):
...
StopIteration
Salah satunya hal yang penting jadi perhatian untuk contoh di atas ialah, nilai dari faktor n masih tetap dikenang pada setiap panggilan peranan.
Berlainan dengan peranan normal, faktor lokal tidak dihancurkan di saat pengakuan yield. Disamping itu, object generator cuman dapat diiterasi untuk sekali saja. Untuk mengulang-ulang kembali proses, kita harus membuat generator lain memakai pengakuan misalnya a = my_gen().
Kita bisa juga memakai generator dalam loop for langsung. Ini karena loop for menggunakan iterator dan lakukan iterasi kepadanya memakai peranan next(). StopIteration automatis dilaksanakan di akhir iterasi.
script.py
IPython Shell
Powered by DataCamp
Di saat contoh di atas digerakkan, hasilnya akan terlihat sebagai berikut:
This is printed first
1
This is printed second
2
This is printed at last
3
Generator Menggunakan Loop
Beberapa contoh di atas jarang-jarang digunakan. Kita pelajarinya cuman untuk tahu teknisnya apa yang sebetulnya terjadi pada generator.
Biasanya, peranan generator diaplikasikan pada loop yang mempunyai keadaan terminasi (pemberhentian) yang tepat.
Silahkan kita bikin contoh generator yang berperan mengubah sebuah string.
script.py
IPython Shell
Powered by DataCamp
Pada contoh di atas, kita memakai peranan range() untuk memperoleh index secara kebalik yang dipakai dalam loop for.
Peranan generator semacam itu bukan hanya berlaku untuk string, tetapi juga untuk iterable yang lain seperti daftar, tuple, dan lain - lain.
Generator Expression
Generator simpel dapat dibikin dengan memakai generator expression. Dengan generator expression ini, pembikinan generator jadi gampang. Serupa dengan peranan lambda yang membuat peranan anonim, generator expression membuat suatu peranan generator anonim.
Sintaks dari generator expression serupa dengan daftar comprehension. Namun pertanda kurung [ ] diganti dengan pertanda kurung ( ). Ketidaksamaan khusus di antara daftar comprehension dengan generator expression ialah, daftar comprehension langsung hasilkan keseluruhnya anggota daftar, sedang generator expression hasilkannya satu poin per satu waktu.
Type seperti generator expression ini kerap disebutkan type lazy (malas), hanya karena menghasilkan poin di saat disuruh. Perihal ini pula yang mengakibatkan generator expression lebih irit memory daripada daftar comprehension.
script.py
IPython Shell
Powered by DataCamp
Kita dapat saksikan di atas, jika generator expression tidak langsung menghasilkan hasil keseluruhannya. Generator expression ini cuman kembalikan poin jika disuruh.
script.py
IPython Shell
Powered by DataCamp
Generator expression bisa juga dipakai sebagai argument peranan. Oleh karenanya, pertanda kurungnya dapat di hilangkan. Misalkan pada peranan sum() dan max() sebagai 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
Argumen Pemakaian Generator
Ada banyak hal sebagai argumen pemakaian generator, yakni seperti berikut:
1. Gampang diaplikasikan
Generator dapat diaplikasikan lebih gampang dan singkat dibanding dengan kelas iterator. Berikut contoh pemakaian kelas iterator untuk hasilkan deret bilangan pangkat 2 dari 0 sampai yang bilangan ditetapkan.
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 hasilnya sama dengan memakai peranan generator.
def PowTwoGen(max = 0):
n = 0
while n < max:
yield 2 ** n
n += 1
Dari contoh di atas, kelihatan jika pemakaian generator lebih gampang dan singkat dibanding iterator.
2. Lebih Irit Memory
Peranan biasa yang dibikin untuk hasilkan sequence, akan simpan keseluruhnya sequence saat sebelum kembalikan hasilnya. Ini akan habiskan memory jika jumlah poinnya besar sekali. Saat itu, generator lebih irit memory hanya karena menghasilkan poin satu-satu yakni cuman saat diundang.
3. Merepresentasikan Stream Tidak Berhingga (Infinite Stream)
Generator ialah langkah yang terbagus untuk sebagai wakil saluran data yang tidak berhingga. Stream (saluran) data yang tidak berhingga, tidak dapat diletakkan dalam memory, hingga pas memakai generator. Berikut contoh untuk menghidupkan semua bilangan genap yang ada (minimal secara teoritis saja)
def all_even():
n = 0
while True:
yield n
n += 2
4. Pipelining Generator
Pipeline ialah jadikan input dari sebuah proses jadi dari proses operasi lainnya. Generator dapat dipakai untuk pipeline dari rangkaian operasi. Ini semakin lebih terang jika digambarkan dengan contoh.
Anggaplah kita memiliki sebuah file log dari rantai makanan cepat sajian populer. File log ini mempunyai sebuah kolom (kolom keempat) yang menulis jumlah pizza yang terjual tiap jam dan kita ingin menjumlahkannya untuk memperoleh jumlah pizza yang terjual dalam lima tahun.
Kita simpulkan jika semuanya yang kosong di kolom ke 4 sebagai 'N/A'. Karena itu, generator yang dapat diaplikasikan untuk ini ialah sebagai 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("Keseluruhan pizza terjual = ", sum(per_jam))