Kata Kunci yield di Python: Apa Itu dan Cara Menggunakannya
Kata kunci yield di Python mengubah fungsi biasa menjadi generator, yang menghasilkan deret nilai sesuai permintaan alih-alih menghitung semuanya sekaligus.
Fungsi Python tidak selalu memiliki pernyataan return. Fungsi generator adalah fungsi yang memiliki kata kunci yield alih-alih return.
Fungsi-fungsi ini menghasilkan iterator generator, yaitu objek yang merepresentasikan aliran data. Elemen yang direpresentasikan oleh sebuah iterator dibuat dan dihasilkan hanya saat diperlukan. Jenis evaluasi ini sering disebut sebagai lazy evaluation.
Saat bekerja dengan dataset besar, generator menawarkan alternatif yang hemat memori dibanding menyimpan data dalam list, tuple, dan struktur data lain yang memerlukan ruang memori untuk setiap elemennya. Fungsi generator juga dapat membuat iterator tak hingga, yang tidak mungkin dilakukan dengan struktur yang dievaluasi secara eager seperti list dan tuple.
Sebelum mulai, mari rekap perbedaan antara fungsi dan generator:
Fitur
Fungsi
Generator
Produksi Nilai
Mengembalikan semua nilai sekaligus
Menghasilkan nilai satu per satu, sesuai permintaan
Eksekusi
Dieksekusi sampai selesai sebelum mengembalikan hasil
Berhenti sejenak setelah menghasilkan nilai, dilanjutkan saat nilai berikutnya diminta
Kata Kunci
return
yield
Penggunaan Memori
Berpotensi tinggi, menyimpan seluruh deret di memori
Rendah, hanya menyimpan nilai saat ini dan state untuk berikutnya
Iterasi
Dapat diiterasi berkali-kali, tetapi perlu menyimpan seluruh deret
Dirancang untuk iterasi sekali lintas, lebih efisien untuk deret besar atau tak hingga
Menggunakan yield di Python untuk Membuat Fungsi Generator
Istilah generator di Python dapat merujuk pada iterator generator atau fungsi generator. Keduanya berbeda tetapi saling terkait di Python. Dalam tutorial ini, istilah lengkap sering digunakan untuk menghindari kebingungan.
Mari telusuri fungsi generator terlebih dahulu. Fungsi generator tampak mirip dengan fungsi biasa tetapi berisi kata kunci yield alih-alih return.
Saat sebuah program Python memanggil fungsi generator, ia membuat iterator generator. Iterator menghasilkan nilai sesuai permintaan dan menghentikan eksekusi sampai nilai lain diperlukan. Mari lihat contoh untuk menjelaskan konsep ini dan menunjukkan perbedaan antara fungsi biasa dan fungsi generator.
Menggunakan fungsi biasa
Pertama, mari mendefinisikan fungsi biasa yang berisi pernyataan return. Fungsi ini menerima deret kata dan sebuah huruf, lalu mengembalikan list yang berisi jumlah kemunculan huruf tersebut di setiap kata:
deffind_letter_occurrences(words, letter):
output =[]for word in words:
output.append(word.count(letter))return output
print(
find_letter_occurrences(["apple","banana","cherry"],"a"))Didukung oleh
Fungsi tersebut menghasilkan list berisi 1, 3, dan 0 karena ada satu a pada apple, tiga kemunculan a pada banana, dan tidak ada pada cherry. Fungsi yang sama dapat direfaktor untuk menggunakan list comprehension alih-alih menginisialisasi list kosong dan menggunakan.append():
deffind_letter_occurrences(words, letter):return[word.count(letter)for word in words]Didukung oleh
Fungsi biasa ini mengembalikan list yang berisi semua hasil setiap kali dipanggil. Namun, jika list kata sangat besar, memanggil fungsi biasa ini membebani kebutuhan memori karena program membuat dan menyimpan list baru dengan ukuran yang sama seperti aslinya. Jika fungsi ini digunakan berulang pada beberapa argumen masukan, atau fungsi serupa melakukan operasi lain pada data asli, tekanan pada memori dapat meningkat dengan cepat.
Menggunakan fungsi generator
Sebagai gantinya, kita dapat menggunakan fungsi generator:
deffind_letter_occurrences(words, letter):for word in words:yield word.count(letter)
words =["apple","banana","cherry"]
letter ="a"
output = find_letter_occurrences(words, letter)print(output)Didukung oleh
<generator object find_letter_occurrences at 0x102935e00>Didukung oleh
Fungsi tersebut menyertakan kata kunci yield keyword alih-alih return. Fungsi generator ini mengembalikan objek generator saat dipanggil, yang ditetapkan ke output. Objek ini adalah sebuah iterator. Objek ini tidak berisi data jumlah kemunculan huruf pada setiap kata. Sebaliknya, generator akan membuat dan menghasilkan nilai saat dibutuhkan. Mari ambil nilai pertama dari iterator generator ini:
Fungsi bawaan next() adalah salah satu cara untuk mendapatkan nilai berikutnya dari sebuah iterator. Kita akan melihat cara lain nanti dalam tutorial ini.
Kode dalam fungsi generator dieksekusi hingga program mencapai baris dengan kata kunci yield. Pada contoh ini, loop for memulai iterasi pertama dan mengambil elemen pertama dalam list words. Metode string .count() mengembalikan bilangan bulat, yaitu 1 dalam kasus ini, karena ada satu kemunculan a pada apple. Generator menghasilkan nilai ini, yang dikembalikan oleh next(output).
Generator output berhenti sejenak eksekusinya pada titik ini. Jadi, generator menyelesaikan iterasi pertama dari loop for dan menemukan jumlah kemunculan huruf a pada kata pertama dalam list kata. Sekarang ia menunggu hingga dibutuhkan lagi.
Jika fungsi bawaan next() dipanggil lagi dengan argumen output, generator akan melanjutkan eksekusi dari titik saat ia berhenti:
Generator melanjutkan dari baris dengan yield pada iterasi pertama loop for. Karena loop for tidak memiliki baris kode lebih lanjut, ia kembali ke atas loop dan mengambil elemen kedua dari list words. Nilai yang dikembalikan oleh .count() adalah 3 dalam kasus ini, dan nilai ini dihasilkan. Generator kembali berhenti sejenak pada titik eksekusi ini.
Panggilan ketiga ke next() melanjutkan eksekusi ini:
Iterasi kedua mencapai akhir loop for, yang kemudian berlanjut ke iterasi ketiga. Kode bergerak ke baris dengan yield lagi, kali ini menghasilkan bilangan bulat 0 karena tidak ada kemunculan a pada cherry.
Generator kembali berhenti sejenak. Program hanya menentukan nasib generator saat kita memanggil next() untuk keempat kalinya:
Traceback (most recent call last):
...
StopIterationDidukung oleh
Eksekusi dilanjutkan dari akhir iterasi ketiga loop for. Namun, loop telah mencapai akhir iterasinya karena tidak ada lagi elemen dalam list words. Generator menimbulkan pengecualian StopIteration.
Dalam sebagian besar kasus penggunaan, elemen generator tidak diakses langsung menggunakan next() melainkan melalui proses iterasi lain. Pengecualian StopIteration menandakan akhir proses iterasi. Kita akan mengeksplorasi ini lebih lanjut pada bagian berikut dari tutorial ini.
Python memiliki cara lain untuk membuat iterator generator ketika operasinya dapat direpresentasikan oleh satu ekspresi, seperti pada contoh sebelumnya. Iterator generator output dapat dibuat menggunakan ekspresi generator:
words =["apple","banana","cherry"]
letter ="a"
output =(word.count(letter)for word in words)print(next(output))print(next(output))print(next(output))print(next(output))Didukung oleh
Ekspresi dalam tanda kurung yang ditetapkan ke output adalah ekspresi generator, yang membuat iterator generator serupa dengan yang dihasilkan oleh fungsi generator find_letter_occurrences().
Mari akhiri bagian ini dengan contoh lain fungsi generator untuk menyoroti bagaimana eksekusi berhenti dan dilanjutkan setiap kali sebuah elemen dibutuhkan:
defshow_status():print("Start")yieldprint("Middle")yieldprint("End")yield
status = show_status()next(status)Didukung oleh
Fungsi generator ini tidak memiliki loop. Sebaliknya, ia berisi tiga baris yang memiliki kata kunci yield. Kode membuat iterator generator status saat memanggil fungsi generator show_status(). Saat pertama kali program memanggil next(status), generator memulai eksekusi. Ia mencetak string "Start" dan berhenti setelah ekspresi yield pertama. Generator menghasilkan None karena tidak ada objek yang mengikuti kata kunci yield.
Program mencetak string "Middle" hanya ketika next() dipanggil untuk kedua kalinya:
Generator berhenti pada ekspresi yield terakhir. Ia akan menimbulkan pengecualian StopIteration saat program berikutnya meminta nilai dari iterator generator ini:
Traceback (most recent call last):
...
StopIterationDidukung oleh
Kita akan mengeksplorasi lebih banyak cara menggunakan generator di bagian berikutnya.
Bekerja Dengan Iterator Generator
Fungsi generator membuat iterator generator, dan iterator bersifat iterable. Mari uraikan frasa ini. Setiap kali program memanggil fungsi generator, ia membuat sebuah iterator. Karena iterator bersifat iterable, ia dapat digunakan dalam loop for dan proses iteratif lainnya.
Karena itu, fungsi bawaan next() bukan satu-satunya cara untuk mengakses elemen dalam sebuah iterator. Bagian ini mengeksplorasi cara lain untuk bekerja dengan generator.
Menggunakan protokol iterasi Python dengan iterator generator
Mari tinjau kembali fungsi generator dari bagian sebelumnya dalam tutorial ini:
deffind_letter_occurrences(words, letter):for word in words:yield word.count(letter)
words =["apple","banana","cherry"]
letter ="a"
output = find_letter_occurrences(words, letter)for value in output:print(value)Didukung oleh
Alih-alih menggunakan next() beberapa kali, versi kode ini menggunakan iterator generator output dalam loop for. Karena iterator bersifat iterable, ia dapat digunakan dalam loop for. Loop mengambil item dari iterator generator hingga tidak ada nilai yang tersisa.
Tidak seperti struktur data seperti list dan tuple, sebuah iterator hanya dapat digunakan sekali. Kode tidak akan mencetak nilai lagi jika kita mencoba menjalankan loop for yang sama untuk kedua kalinya:
deffind_letter_occurrences(words, letter):for word in words:yield word.count(letter)
words =["apple","banana","cherry"]
letter ="a"
output = find_letter_occurrences(words, letter)print("First attempt:")for value in output:print(value)print("Second attempt:")for value in output:print(value)Didukung oleh
Iterator habis oleh loop for pertama, sehingga tidak dapat lagi menghasilkan nilai. Jika generator dibutuhkan lagi setelah habis, kita harus membuat iterator generator baru dari fungsi generator.
Dimungkinkan juga memiliki beberapa iterator generator yang ada pada saat yang sama dalam sebuah program:
deffind_letter_occurrences(words, letter):for word in words:yield word.count(letter)
words =["apple","banana","cherry"]
letter ="a"
first_output = find_letter_occurrences(words, letter)
second_output = find_letter_occurrences(words, letter)print("First value of first_output:")print(next(first_output))print("Values of second_output:")for value in second_output:print(value)print("Remaining values of first_output:")for value in first_output:print(value)Didukung oleh
First value of first_output:
1
Values of second_output:
1
3
0
Remaining values of first_output:
3
0Didukung oleh
Fungsi generator find_letter_occurrences() membuat dua iterator generator: first_output dan second_output. Meskipun kedua iterator merujuk pada data yang sama dalam list words, keduanya berjalan secara independen satu sama lain.
Contoh ini mengambil nilai pertama dari first_output menggunakan next(). Iterator generator menghasilkan 1 dan berhenti sejenak pada titik ini. Program selanjutnya melakukan loop melalui second_output. Karena generator ini belum menghasilkan nilai apa pun, loop akan melalui semua nilai yang dihasilkan oleh iterator kedua. Terakhir, ada loop for lain yang mengiterasi first_output. Namun, iterator ini sudah menghasilkan nilai pertamanya lebih awal dalam program. Loop berjalan melalui nilai-nilai yang tersisa dalam iterator ini.
Loop for bukan satu-satunya proses yang dapat digunakan untuk mengiterasi iterator generator:
print(*find_letter_occurrences(words, letter))print(sorted(find_letter_occurrences(words, letter)))Didukung oleh
Pada contoh ini, program memanggil fungsi generator secara langsung untuk membuat dan menggunakan iterator generator alih-alih menugaskannya ke variabel. Pada contoh pertama, iterator di-unpack menggunakan notasi bintang. Proses ini mengandalkan protokol iterasi yang sama seperti loop for.
Pada contoh kedua, iterator generator diteruskan ke fungsi bawaan sorted(), yang memerlukan argumen iterable. Generator bersifat iterable, sehingga dapat digunakan kapan pun iterasi Python terjadi.
Membuat iterator tak hingga
Sebuah generator menghasilkan nilai dan berhenti sejenak hingga nilai berikutnya dibutuhkan. Setiap kali kode meminta nilai dari sebuah iterator, kode di dalam fungsi generator akan dieksekusi hingga ekspresi yield berikutnya dievaluasi. Pada semua contoh dalam tutorial sejauh ini, fungsi generator memiliki jumlah ekspresi yield yang terbatas. Namun, dimungkinkan untuk membuat generator yang menghasilkan jumlah nilai tak terbatas dengan menggunakan loop while dalam fungsi generator. Pada contoh berikut, generator menghasilkan warna acak dari list warna yang diteruskan ke fungsi generator:
import random
defget_color(colors):whileTrue:yield random.choice(colors)
output_colors = get_color(["red","green","blue"])print("First two colors:")print(next(output_colors))print(next(output_colors))print("Next 10 colors using a 'for' loop:")for _ inrange(10):print(next(output_colors))Didukung oleh
First two colors:
green
red
Next 10 colors using a 'for' loop:
blue
green
green
green
red
red
red
blue
green
redDidukung oleh
Fungsi generator get_color() memiliki ekspresi yield di dalam loop while. Oleh karena itu, kode akan selalu menemui ekspresi yield lain saat mencari nilai berikutnya. Iterator generator output_colors menghasilkan jumlah warna tak terbatas yang dipilih secara acak dari list masukan. Generator ini tidak akan pernah habis.
Tidak mungkin membuat struktur data tak hingga seperti list dan tuple. Generator memungkinkan program membuat iterable tak hingga. Perhatikan bahwa jika iterator generator digunakan langsung dalam loop for, loop akan berjalan selamanya.
Konsep Generator Lanjutan
Generator memiliki kasus penggunaan yang lebih lanjut di Python. Bagian ini akan mengeksplorasi beberapa di antaranya.
Mengirim objek ke dalam generator
Generator juga dapat menerima data tambahan yang dapat digunakan saat mengevaluasi kode. Pernyataan yang berisi kata kunci yield adalah sebuah ekspresi yang dievaluasi menjadi sebuah nilai. Nilai ini dapat ditetapkan ke variabel di dalam fungsi generator. Mari mulai dengan contoh dasar untuk menunjukkan konsep ini:
defgenerator_function():
value =yield1print(f"The yield expression evaluates to: {value}")
value =yield2print(f"The yield expression evaluates to: {value}")
output = generator_function()print(next(output))print(next(output))print(next(output))Didukung oleh
1
The yield expression evaluates to: None
2
The yield expression evaluates to: None
Traceback (most recent call last):
...
StopIterationDidukung oleh
Kata kunci yield di Python membuat sebuah ekspresi yang dievaluasi menjadi sebuah nilai. Namun, nilai ekspresi ini di dalam fungsi generator bukanlah objek yang sama dengan yang dihasilkan oleh generator. Pertimbangkan ekspresi yield yang pertama. Generator menghasilkan bilangan bulat 1. Oleh karena itu, print(next(output)) menampilkan 1 saat pertama kali dipanggil dan menghentikan eksekusi generator.
Namun, ekspresi yield di dalam generator dievaluasi menjadi sebuah objek, yang kodenya ditetapkan ke nama variabel value. Dalam contoh ini, yield menetapkan None ke value. Proses ini diulangi untuk kemunculan kedua yield dalam fungsi generator. Tujuan dari panggilan next() yang ketiga adalah memastikan semua kode dalam fungsi generator dieksekusi.
Mari ganti panggilan next() kedua dan ketiga dengan.send(), yang merupakan metode dalam kelas generator:
defgenerator_function():
value =yield1print(f"The yield expression evaluates to: {value}")
value =yield2print(f"The yield expression evaluates to: {value}")
output = generator_function()print(next(output))print(output.send("Here's a value"))print(output.send("Here's another value"))Didukung oleh
1
The yield expression evaluates to: Here's a value
2
The yield expression evaluates to: Here's another value
Traceback (most recent call last):
...
StopIterationDidukung oleh
Fungsi generatornya tidak berubah. Generator dimulai dengan memanggil next(), dan kodenya berjalan hingga menghasilkan bilangan bulat pertama, 1. Alih-alih menggunakan next() untuk kedua kalinya, program memanggil output.send(). Metode ini mengirimkan sebuah objek ke dalam generator. Pada contoh ini, objeknya adalah sebuah string. Ekspresi yield dalam fungsi generator dievaluasi menjadi string ini, yang ditetapkan ke value. Karena itu, generator dapat menggunakan string tersebut di dalam kodenya.
Panggilan kedua ke .send() mengirimkan objek baru ke generator, yang ditetapkan ke variabel yang sama, value. Generator memunculkan StopIteration setelah pemanggilan print() terakhir karena tidak ada lagi ekspresi yield.
Mari lihat contoh lain menggunakan .send(). Generator berikut menampilkan saldo dalam sebuah akun, dan saldonya dapat diperbarui:
defget_balance(start_balance):
balance = start_balance
whileTrue:
amount =yield balance
if amount isnotNone:
balance += amount
current_balance = get_balance(100)print(next(current_balance))print(current_balance.send(10))print(current_balance.send(-20))print(next(current_balance))Didukung oleh
Fungsi generator memerlukan saldo awal saat dipanggil. Nilai balance dapat berubah seiring generator mengeksekusi kode. Objek apa pun yang dikirim ke generator menggunakan .send() akan ditetapkan ke amount. Variabel ini akan bernilai None jika generator melakukan yield tanpa ada objek yang dikirim ke sana, atau akan berisi objek yang dikirim menggunakan .send().
Iterator generator current_balance dimulai dengan saldo $100. Generator dimulai dengan memanggil next(), yang mengeksekusi kode hingga nilai pertama di-yield.
Setelah generator dimulai, eksekusi dapat dilanjutkan menggunakan .send() alih-alih next(). Generator menambahkan nilai yang dikirim ke saldo. Jika tidak ada nilai yang dikirim, misalnya dengan memanggil next() lagi, generator akan melakukan yield saldo yang tidak berubah.
Melakukan yield langsung dari iterable lain
Generator Python juga dapat melakukan yield nilai secara langsung dari generator atau iterable lain menggunakan sintaks yield from. Mari lihat contoh fungsi generator yang melakukan yield nilai dari daftar bertingkat:
defflatten(nested_list):for item in nested_list:ifisinstance(item,list):yieldfrom flatten(item)else:yield item
nested_list =[1,[2,3],[4,[5,6]],7]print(list(flatten(nested_list)))Didukung oleh
Fungsi generator menerima sebuah daftar, yang dapat mencakup daftar bersarang di dalamnya. Loop for mengiterasi item-item dalam daftar. Setiap item pada daftar terluar bisa berupa sebuah nilai, dalam hal ini sebuah bilangan bulat, atau daftar lain. Saat item bukan sebuah daftar, generator melakukan yield item tersebut.
Namun, ketika item adalah sebuah daftar, generator secara rekursif memanggil fungsi generator flatten() lagi dengan daftar dalam sebagai argumen. Ini membuat iterator generator lain, yang menggunakan daftar dalam sebagai sumber datanya. Jika baris ini menggunakan ekspresi yield, generator pertama akan melakukan yield generator kedua. Sebaliknya, dengan menggunakan yield from, generator pertama melakukan yield nilai-nilai dari generator kedua.
Ringkasan: yield vs. return
Definisi fungsi dengan return dan yield terlihat mirip, tetapi perilakunya berbeda. Mari kita rangkum perbedaan utamanya:
Fungsi Biasa
Fungsi Generator
Kata Kunci
return (implisit jika tidak digunakan secara eksplisit)
yield
Saat Dipanggil
Mengeksekusi kode hingga mencapai return, lalu mengembalikan nilai akhir
Membuat sebuah iterator generator
Terminasi
Diakhiri oleh pernyataan return
Dijeda oleh yield, dapat dilanjutkan kemudian
Nilai Kembalian
Objek tunggal (dapat berupa struktur data)
Iterator generator
Ekspresi Yield
Tidak berlaku (membuat sebuah pernyataan)
Dievaluasi menjadi None atau nilai yang dikirim menggunakan .send()
Kasus Penggunaan
Ideal untuk mengembalikan hasil akhir
Ideal untuk membuat aliran data, terutama deret besar atau tak hingga
Kesimpulan
Kata kunci yield Python digunakan dalam fungsi untuk mendefinisikan fungsi generator. Saat dipanggil, fungsi-fungsi ini membuat iterator generator. Generator adalah contoh evaluasi malas (lazy evaluation) di Python, di mana ekspresi dievaluasi ketika nilainya dibutuhkan alih-alih saat mengeksekusi ekspresi tersebut. Karena itu, ekspresi yield berguna untuk membuat aliran data di mana nilai-nilai dihasilkan sesuai permintaan tanpa perlu menyimpannya di memori.
Pertimbangan efisiensi penting saat menangani set data besar yang memerlukan banyak operasi. Iterator generator Python adalah salah satu alat utama yang dibutuhkan untuk memanipulasi data dalam jumlah besar secara efisien.
Saya belajar Fisika dan Matematika pada tingkat sarjana di University of Malta. Kemudian, saya pindah ke London dan meraih gelar PhD dalam bidang Fisika dari Imperial College. Saya meneliti teknik optik baru untuk memindai retina manusia. Sekarang, saya berfokus menulis tentang Python, berkomunikasi tentang Python, dan mengajar Python.
Temukan alasan mengapa Anda sebaiknya (tidak) menggunakan spaghetti plot untuk menyampaikan ketidakpastian jalur prediksi badai serta dampaknya terhadap interpretasi.
Kuasai pertanyaan wawancara basis data, dari konsep SQL dasar hingga skenario desain sistem tingkat lanjut. Panduan mendalam ini mencakup semua yang Anda perlukan untuk sukses di wawancara DBMS dan meraih peran berikutnya.
Pelajari Python untuk pengembangan perangkat lunak, mulai dari menulis fungsi hingga mendefinisikan kelas. Dapatkan keterampilan yang diperlukan untuk memulai karir Anda sebagai pengembang!
Fungsi Python tidak selalu memiliki pernyataan
return. Fungsi generator adalah fungsi yang memiliki kata kunciyieldalih-alihreturn.Fungsi-fungsi ini menghasilkan iterator generator, yaitu objek yang merepresentasikan aliran data. Elemen yang direpresentasikan oleh sebuah iterator dibuat dan dihasilkan hanya saat diperlukan. Jenis evaluasi ini sering disebut sebagai lazy evaluation.
Saat bekerja dengan dataset besar, generator menawarkan alternatif yang hemat memori dibanding menyimpan data dalam list, tuple, dan struktur data lain yang memerlukan ruang memori untuk setiap elemennya. Fungsi generator juga dapat membuat iterator tak hingga, yang tidak mungkin dilakukan dengan struktur yang dievaluasi secara eager seperti list dan tuple.
Sebelum mulai, mari rekap perbedaan antara fungsi dan generator:
Fitur
Fungsi
Generator
Produksi Nilai
Mengembalikan semua nilai sekaligus
Menghasilkan nilai satu per satu, sesuai permintaan
Eksekusi
Dieksekusi sampai selesai sebelum mengembalikan hasil
Berhenti sejenak setelah menghasilkan nilai, dilanjutkan saat nilai berikutnya diminta
Kata Kunci
return
yield
Penggunaan Memori
Berpotensi tinggi, menyimpan seluruh deret di memori
Rendah, hanya menyimpan nilai saat ini dan state untuk berikutnya
Iterasi
Dapat diiterasi berkali-kali, tetapi perlu menyimpan seluruh deret
Dirancang untuk iterasi sekali lintas, lebih efisien untuk deret besar atau tak hingga
Menggunakan
yielddi Python untuk Membuat Fungsi GeneratorIstilah generator di Python dapat merujuk pada iterator generator atau fungsi generator. Keduanya berbeda tetapi saling terkait di Python. Dalam tutorial ini, istilah lengkap sering digunakan untuk menghindari kebingungan.
Mari telusuri fungsi generator terlebih dahulu. Fungsi generator tampak mirip dengan fungsi biasa tetapi berisi kata kunci
yieldalih-alihreturn.Saat sebuah program Python memanggil fungsi generator, ia membuat iterator generator. Iterator menghasilkan nilai sesuai permintaan dan menghentikan eksekusi sampai nilai lain diperlukan. Mari lihat contoh untuk menjelaskan konsep ini dan menunjukkan perbedaan antara fungsi biasa dan fungsi generator.
Menggunakan fungsi biasa
Pertama, mari mendefinisikan fungsi biasa yang berisi pernyataan
return. Fungsi ini menerima deret kata dan sebuah huruf, lalu mengembalikan list yang berisi jumlah kemunculan huruf tersebut di setiap kata:Fungsi tersebut menghasilkan list berisi 1, 3, dan 0 karena ada satu a pada apple, tiga kemunculan a pada banana, dan tidak ada pada cherry. Fungsi yang sama dapat direfaktor untuk menggunakan list comprehension alih-alih menginisialisasi list kosong dan menggunakan
.append():Fungsi biasa ini mengembalikan list yang berisi semua hasil setiap kali dipanggil. Namun, jika list kata sangat besar, memanggil fungsi biasa ini membebani kebutuhan memori karena program membuat dan menyimpan list baru dengan ukuran yang sama seperti aslinya. Jika fungsi ini digunakan berulang pada beberapa argumen masukan, atau fungsi serupa melakukan operasi lain pada data asli, tekanan pada memori dapat meningkat dengan cepat.
Menggunakan fungsi generator
Sebagai gantinya, kita dapat menggunakan fungsi generator:
Fungsi tersebut menyertakan kata kunci
yieldkeyword alih-alihreturn. Fungsi generator ini mengembalikan objek generator saat dipanggil, yang ditetapkan keoutput. Objek ini adalah sebuah iterator. Objek ini tidak berisi data jumlah kemunculan huruf pada setiap kata. Sebaliknya, generator akan membuat dan menghasilkan nilai saat dibutuhkan. Mari ambil nilai pertama dari iterator generator ini:Fungsi bawaan
next()adalah salah satu cara untuk mendapatkan nilai berikutnya dari sebuah iterator. Kita akan melihat cara lain nanti dalam tutorial ini.Kode dalam fungsi generator dieksekusi hingga program mencapai baris dengan kata kunci
yield. Pada contoh ini, loopformemulai iterasi pertama dan mengambil elemen pertama dalam listwords. Metode string.count()mengembalikan bilangan bulat, yaitu 1 dalam kasus ini, karena ada satu kemunculan a pada apple. Generator menghasilkan nilai ini, yang dikembalikan olehnext(output).Generator
outputberhenti sejenak eksekusinya pada titik ini. Jadi, generator menyelesaikan iterasi pertama dari loopfordan menemukan jumlah kemunculan huruf a pada kata pertama dalam list kata. Sekarang ia menunggu hingga dibutuhkan lagi.Jika fungsi bawaan
next()dipanggil lagi dengan argumenoutput, generator akan melanjutkan eksekusi dari titik saat ia berhenti:Generator melanjutkan dari baris dengan
yieldpada iterasi pertama loopfor. Karena loopfortidak memiliki baris kode lebih lanjut, ia kembali ke atas loop dan mengambil elemen kedua dari listwords. Nilai yang dikembalikan oleh.count()adalah 3 dalam kasus ini, dan nilai ini dihasilkan. Generator kembali berhenti sejenak pada titik eksekusi ini.Panggilan ketiga ke
next()melanjutkan eksekusi ini:Iterasi kedua mencapai akhir loop
for, yang kemudian berlanjut ke iterasi ketiga. Kode bergerak ke baris denganyieldlagi, kali ini menghasilkan bilangan bulat 0 karena tidak ada kemunculan a pada cherry.Generator kembali berhenti sejenak. Program hanya menentukan nasib generator saat kita memanggil
next()untuk keempat kalinya:Eksekusi dilanjutkan dari akhir iterasi ketiga loop
for. Namun, loop telah mencapai akhir iterasinya karena tidak ada lagi elemen dalam listwords. Generator menimbulkan pengecualianStopIteration.Dalam sebagian besar kasus penggunaan, elemen generator tidak diakses langsung menggunakan
next()melainkan melalui proses iterasi lain. PengecualianStopIterationmenandakan akhir proses iterasi. Kita akan mengeksplorasi ini lebih lanjut pada bagian berikut dari tutorial ini.Python memiliki cara lain untuk membuat iterator generator ketika operasinya dapat direpresentasikan oleh satu ekspresi, seperti pada contoh sebelumnya. Iterator generator
outputdapat dibuat menggunakan ekspresi generator:Ekspresi dalam tanda kurung yang ditetapkan ke
outputadalah ekspresi generator, yang membuat iterator generator serupa dengan yang dihasilkan oleh fungsi generatorfind_letter_occurrences().Mari akhiri bagian ini dengan contoh lain fungsi generator untuk menyoroti bagaimana eksekusi berhenti dan dilanjutkan setiap kali sebuah elemen dibutuhkan:
Fungsi generator ini tidak memiliki loop. Sebaliknya, ia berisi tiga baris yang memiliki kata kunci
yield. Kode membuat iterator generatorstatussaat memanggil fungsi generatorshow_status(). Saat pertama kali program memanggilnext(status), generator memulai eksekusi. Ia mencetak string"Start"dan berhenti setelah ekspresiyieldpertama. Generator menghasilkanNonekarena tidak ada objek yang mengikuti kata kunciyield.Program mencetak string
"Middle"hanya ketikanext()dipanggil untuk kedua kalinya:Generator berhenti setelah ekspresi
yieldkedua. Panggilan ketiga kenext()mencetak string terakhir,"End":Generator berhenti pada ekspresi
yieldterakhir. Ia akan menimbulkan pengecualianStopIterationsaat program berikutnya meminta nilai dari iterator generator ini:Kita akan mengeksplorasi lebih banyak cara menggunakan generator di bagian berikutnya.
Bekerja Dengan Iterator Generator
Fungsi generator membuat iterator generator, dan iterator bersifat iterable. Mari uraikan frasa ini. Setiap kali program memanggil fungsi generator, ia membuat sebuah iterator. Karena iterator bersifat iterable, ia dapat digunakan dalam loop
fordan proses iteratif lainnya.Karena itu, fungsi bawaan
next()bukan satu-satunya cara untuk mengakses elemen dalam sebuah iterator. Bagian ini mengeksplorasi cara lain untuk bekerja dengan generator.Menggunakan protokol iterasi Python dengan iterator generator
Mari tinjau kembali fungsi generator dari bagian sebelumnya dalam tutorial ini:
Alih-alih menggunakan
next()beberapa kali, versi kode ini menggunakan iterator generatoroutputdalam loopfor. Karena iterator bersifat iterable, ia dapat digunakan dalam loopfor. Loop mengambil item dari iterator generator hingga tidak ada nilai yang tersisa.Tidak seperti struktur data seperti list dan tuple, sebuah iterator hanya dapat digunakan sekali. Kode tidak akan mencetak nilai lagi jika kita mencoba menjalankan loop
foryang sama untuk kedua kalinya:Iterator habis oleh loop
forpertama, sehingga tidak dapat lagi menghasilkan nilai. Jika generator dibutuhkan lagi setelah habis, kita harus membuat iterator generator baru dari fungsi generator.Dimungkinkan juga memiliki beberapa iterator generator yang ada pada saat yang sama dalam sebuah program:
Fungsi generator
find_letter_occurrences()membuat dua iterator generator:first_outputdansecond_output. Meskipun kedua iterator merujuk pada data yang sama dalam listwords, keduanya berjalan secara independen satu sama lain.Contoh ini mengambil nilai pertama dari
first_outputmenggunakannext(). Iterator generator menghasilkan 1 dan berhenti sejenak pada titik ini. Program selanjutnya melakukan loop melaluisecond_output. Karena generator ini belum menghasilkan nilai apa pun, loop akan melalui semua nilai yang dihasilkan oleh iterator kedua. Terakhir, ada loopforlain yang mengiterasifirst_output. Namun, iterator ini sudah menghasilkan nilai pertamanya lebih awal dalam program. Loop berjalan melalui nilai-nilai yang tersisa dalam iterator ini.Loop
forbukan satu-satunya proses yang dapat digunakan untuk mengiterasi iterator generator:Pada contoh ini, program memanggil fungsi generator secara langsung untuk membuat dan menggunakan iterator generator alih-alih menugaskannya ke variabel. Pada contoh pertama, iterator di-unpack menggunakan notasi bintang. Proses ini mengandalkan protokol iterasi yang sama seperti loop
for.Pada contoh kedua, iterator generator diteruskan ke fungsi bawaan
sorted(), yang memerlukan argumen iterable. Generator bersifat iterable, sehingga dapat digunakan kapan pun iterasi Python terjadi.Membuat iterator tak hingga
Sebuah generator menghasilkan nilai dan berhenti sejenak hingga nilai berikutnya dibutuhkan. Setiap kali kode meminta nilai dari sebuah iterator, kode di dalam fungsi generator akan dieksekusi hingga ekspresi
yieldberikutnya dievaluasi. Pada semua contoh dalam tutorial sejauh ini, fungsi generator memiliki jumlah ekspresiyieldyang terbatas. Namun, dimungkinkan untuk membuat generator yang menghasilkan jumlah nilai tak terbatas dengan menggunakan loopwhiledalam fungsi generator. Pada contoh berikut, generator menghasilkan warna acak dari list warna yang diteruskan ke fungsi generator:Fungsi generator
get_color()memiliki ekspresiyielddi dalam loopwhile. Oleh karena itu, kode akan selalu menemui ekspresiyieldlain saat mencari nilai berikutnya. Iterator generatoroutput_colorsmenghasilkan jumlah warna tak terbatas yang dipilih secara acak dari list masukan. Generator ini tidak akan pernah habis.Tidak mungkin membuat struktur data tak hingga seperti list dan tuple. Generator memungkinkan program membuat iterable tak hingga. Perhatikan bahwa jika iterator generator digunakan langsung dalam loop
for, loop akan berjalan selamanya.Konsep Generator Lanjutan
Generator memiliki kasus penggunaan yang lebih lanjut di Python. Bagian ini akan mengeksplorasi beberapa di antaranya.
Mengirim objek ke dalam generator
Generator juga dapat menerima data tambahan yang dapat digunakan saat mengevaluasi kode. Pernyataan yang berisi kata kunci
yieldadalah sebuah ekspresi yang dievaluasi menjadi sebuah nilai. Nilai ini dapat ditetapkan ke variabel di dalam fungsi generator. Mari mulai dengan contoh dasar untuk menunjukkan konsep ini:Kata kunci
yielddi Python membuat sebuah ekspresi yang dievaluasi menjadi sebuah nilai. Namun, nilai ekspresi ini di dalam fungsi generator bukanlah objek yang sama dengan yang dihasilkan oleh generator. Pertimbangkan ekspresiyieldyang pertama. Generator menghasilkan bilangan bulat 1. Oleh karena itu,print(next(output))menampilkan 1 saat pertama kali dipanggil dan menghentikan eksekusi generator.Namun, ekspresi
yielddi dalam generator dievaluasi menjadi sebuah objek, yang kodenya ditetapkan ke nama variabelvalue. Dalam contoh ini,yieldmenetapkanNonekevalue. Proses ini diulangi untuk kemunculan keduayielddalam fungsi generator. Tujuan dari panggilannext()yang ketiga adalah memastikan semua kode dalam fungsi generator dieksekusi.Mari ganti panggilan
next()kedua dan ketiga dengan.send(), yang merupakan metode dalam kelas generator:Fungsi generatornya tidak berubah. Generator dimulai dengan memanggil
next(), dan kodenya berjalan hingga menghasilkan bilangan bulat pertama, 1. Alih-alih menggunakannext()untuk kedua kalinya, program memanggiloutput.send(). Metode ini mengirimkan sebuah objek ke dalam generator. Pada contoh ini, objeknya adalah sebuah string. Ekspresiyielddalam fungsi generator dievaluasi menjadi string ini, yang ditetapkan kevalue. Karena itu, generator dapat menggunakan string tersebut di dalam kodenya.Panggilan kedua ke
.send()mengirimkan objek baru ke generator, yang ditetapkan ke variabel yang sama,value. Generator memunculkanStopIterationsetelah pemanggilanprint()terakhir karena tidak ada lagi ekspresiyield.Mari lihat contoh lain menggunakan
.send(). Generator berikut menampilkan saldo dalam sebuah akun, dan saldonya dapat diperbarui:Fungsi generator memerlukan saldo awal saat dipanggil. Nilai
balancedapat berubah seiring generator mengeksekusi kode. Objek apa pun yang dikirim ke generator menggunakan.send()akan ditetapkan keamount. Variabel ini akan bernilaiNonejika generator melakukan yield tanpa ada objek yang dikirim ke sana, atau akan berisi objek yang dikirim menggunakan.send().Iterator generator
current_balancedimulai dengan saldo $100. Generator dimulai dengan memanggilnext(), yang mengeksekusi kode hingga nilai pertama di-yield.Setelah generator dimulai, eksekusi dapat dilanjutkan menggunakan
.send()alih-alihnext(). Generator menambahkan nilai yang dikirim ke saldo. Jika tidak ada nilai yang dikirim, misalnya dengan memanggilnext()lagi, generator akan melakukan yield saldo yang tidak berubah.Melakukan yield langsung dari iterable lain
Generator Python juga dapat melakukan yield nilai secara langsung dari generator atau iterable lain menggunakan sintaks
yield from. Mari lihat contoh fungsi generator yang melakukan yield nilai dari daftar bertingkat:Fungsi generator menerima sebuah daftar, yang dapat mencakup daftar bersarang di dalamnya. Loop
formengiterasi item-item dalam daftar. Setiap item pada daftar terluar bisa berupa sebuah nilai, dalam hal ini sebuah bilangan bulat, atau daftar lain. Saat item bukan sebuah daftar, generator melakukan yield item tersebut.Namun, ketika item adalah sebuah daftar, generator secara rekursif memanggil fungsi generator
flatten()lagi dengan daftar dalam sebagai argumen. Ini membuat iterator generator lain, yang menggunakan daftar dalam sebagai sumber datanya. Jika baris ini menggunakan ekspresiyield, generator pertama akan melakukan yield generator kedua. Sebaliknya, dengan menggunakanyield from, generator pertama melakukan yield nilai-nilai dari generator kedua.Ringkasan:
yieldvs.returnDefinisi fungsi dengan
returndanyieldterlihat mirip, tetapi perilakunya berbeda. Mari kita rangkum perbedaan utamanya:Fungsi Biasa
Fungsi Generator
Kata Kunci
return (implisit jika tidak digunakan secara eksplisit)
yield
Saat Dipanggil
Mengeksekusi kode hingga mencapai return, lalu mengembalikan nilai akhir
Membuat sebuah iterator generator
Terminasi
Diakhiri oleh pernyataan return
Dijeda oleh yield, dapat dilanjutkan kemudian
Nilai Kembalian
Objek tunggal (dapat berupa struktur data)
Iterator generator
Ekspresi Yield
Tidak berlaku (membuat sebuah pernyataan)
Dievaluasi menjadi None atau nilai yang dikirim menggunakan .send()
Kasus Penggunaan
Ideal untuk mengembalikan hasil akhir
Ideal untuk membuat aliran data, terutama deret besar atau tak hingga
Kesimpulan
Kata kunci
yieldPython digunakan dalam fungsi untuk mendefinisikan fungsi generator. Saat dipanggil, fungsi-fungsi ini membuat iterator generator. Generator adalah contoh evaluasi malas (lazy evaluation) di Python, di mana ekspresi dievaluasi ketika nilainya dibutuhkan alih-alih saat mengeksekusi ekspresi tersebut. Karena itu, ekspresiyieldberguna untuk membuat aliran data di mana nilai-nilai dihasilkan sesuai permintaan tanpa perlu menyimpannya di memori.Pertimbangan efisiensi penting saat menangani set data besar yang memerlukan banyak operasi. Iterator generator Python adalah salah satu alat utama yang dibutuhkan untuk memanipulasi data dalam jumlah besar secara efisien.
Jika Anda ingin mempelajari lebih lanjut tentang Python, lihat jalur karier Python Developer ini.