Kursus
Iterator adalah objek yang dapat diiterasi. Ini adalah fitur umum dalam bahasa pemrograman Python, yang kerap digunakan untuk perulangan dan list comprehension. Objek apa pun yang dapat menghasilkan sebuah iterator disebut iterable.
Ada banyak pekerjaan yang diperlukan untuk membangun sebuah iterator. Misalnya, implementasi setiap objek iterator harus memiliki metode __iter__() dan __next__() . Selain prasyarat di atas, implementasinya juga harus memiliki cara untuk melacak status internal objek dan memunculkan pengecualian StopIteration saat tidak ada lagi nilai yang dapat dikembalikan. Aturan-aturan ini dikenal sebagai protokol iterator.
Mengimplementasikan iterator Anda sendiri adalah proses yang panjang, dan tidak selalu diperlukan. Alternatif yang lebih sederhana adalah menggunakan objek generator. Generator adalah jenis fungsi khusus yang menggunakan kata kunci yield untuk mengembalikan sebuah iterator yang dapat diiterasi, satu nilai pada satu waktu.
Kemampuan membedakan kapan perlu mengimplementasikan iterator atau menggunakan generator akan meningkatkan keterampilan Anda sebagai programmer Python. Dalam sisa tutorial ini, kami akan menekankan perbedaan antara kedua objek tersebut, yang akan membantu Anda memutuskan mana yang terbaik untuk digunakan dalam berbagai situasi.
Glosarium
|
Istilah |
Definisi |
|
Iterable |
Objek Python yang dapat dilintasi atau diiterasi dalam sebuah loop. Contoh iterable meliputi list, set, tuple, dictionary, string, dan sebagainya. |
|
Iterator |
Iterator adalah objek yang dapat diiterasi. Dengan demikian, iterator berisi sejumlah nilai yang dapat dihitung. |
|
Generator |
Jenis fungsi khusus yang tidak mengembalikan satu nilai: ia mengembalikan objek iterator dengan serangkaian nilai. |
|
Evaluasi Malas (Lazy Evaluation) |
Strategi evaluasi di mana objek tertentu hanya dihasilkan saat diperlukan. Konsekuensinya, sebagian kalangan pengembang juga menyebut evaluasi malas sebagai “call-by-need.” |
|
Protokol Iterator |
Serangkaian aturan yang harus diikuti untuk mendefinisikan sebuah iterator di Python. |
|
next() |
Fungsi bawaan yang digunakan untuk mengembalikan item berikutnya dalam sebuah iterator. |
|
iter() |
Fungsi bawaan yang digunakan untuk mengonversi sebuah iterable menjadi iterator. |
|
yield() |
Kata kunci Python yang mirip dengan return, tetapi |
Iterator & Iterable Python
Iterable adalah objek yang mampu mengembalikan anggotanya satu per satu – mereka dapat diiterasi. Struktur data Python bawaan yang populer seperti list, tuple, dan set termasuk iterable. Struktur data lain seperti string dan dictionary juga dianggap iterable: string dapat diiterasi per karakternya, dan kunci-kunci dictionary dapat diiterasi. Sebagai patokan, anggap objek apa pun yang dapat diiterasi dalam for-loop sebagai iterable.
Mengeksplorasi iterable Python dengan contoh
Berdasarkan definisi ini, kita dapat menyimpulkan bahwa semua iterator juga merupakan iterable. Namun, tidak setiap iterable merupakan iterator. Sebuah iterable menghasilkan iterator hanya ketika ia diiterasi.
Untuk mendemonstrasikan fungsionalitas ini, kita akan membuat sebuah list, yang merupakan iterable, dan menghasilkan iterator dengan memanggil fungsi bawaan iter() pada list tersebut.
list_instance = [1, 2, 3, 4]
print(iter(list_instance))
"""
<list_iterator object at 0x7fd946309e90>
"""
Walaupun list itu sendiri bukan iterator, pemanggilan fungsi iter() mengonversinya menjadi iterator dan mengembalikan objek iterator.
Untuk menunjukkan bahwa tidak semua iterable adalah iterator, kita akan membuat objek list yang sama dan mencoba memanggil fungsi next(), yang digunakan untuk mengembalikan item berikutnya dalam sebuah iterator.
list_instance = [1, 2, 3, 4]
print(next(list_instance))
"""
--------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-2-0cb076ed2d65> in <module>()
3 print(iter(list_instance))
4
----> 5 print(next(list_instance))
TypeError: 'list' object is not an iterator
"""
Pada kode di atas, Anda dapat melihat bahwa mencoba memanggil fungsi next() pada list memunculkan TypeError – pelajari lebih lanjut tentang Penanganan Exception dan Error di Python. Perilaku ini terjadi karena objek list adalah iterable, bukan iterator.
Mengeksplorasi iterator Python dengan contoh
Jadi, jika tujuannya adalah mengiterasi sebuah list, maka objek iterator harus dibuat terlebih dahulu. Barulah kita dapat mengelola iterasi melalui nilai-nilai dalam list.
# instantiate a list object
list_instance = [1, 2, 3, 4]
# convert the list to an iterator
iterator = iter(list_instance)
# return items one at a time
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
"""
1
2
3
4
"""
Python secara otomatis menghasilkan objek iterator setiap kali Anda mencoba melakukan perulangan pada objek iterable.
# instantiate a list object
list_instance = [1, 2, 3, 4]
# loop through the list
for item in list_instance:
print(item)
"""
1
2
3
4
"""
Ketika pengecualian StopIteration tertangkap, loop akan berakhir.
Nilai-nilai yang diperoleh dari sebuah iterator hanya dapat diambil dari kiri ke kanan. Python tidak memiliki fungsi previous() untuk memungkinkan pengembang bergerak mundur melalui sebuah iterator.
Sifat malas dari iterator
Dimungkinkan untuk mendefinisikan beberapa iterator berdasarkan objek iterable yang sama. Setiap iterator akan mempertahankan status kemajuannya sendiri. Dengan demikian, dengan mendefinisikan beberapa instance iterator dari sebuah objek iterable, dimungkinkan untuk mengiterasi hingga akhir pada satu instance sementara instance lainnya tetap di awal.
list_instance = [1, 2, 3, 4]
iterator_a = iter(list_instance)
iterator_b = iter(list_instance)
print(f"A: {next(iterator_a)}")
print(f"A: {next(iterator_a)}")
print(f"A: {next(iterator_a)}")
print(f"A: {next(iterator_a)}")
print(f"B: {next(iterator_b)}")
"""
A: 1
A: 2
A: 3
A: 4
B: 1
"""
Perhatikan iterator_b mencetak elemen pertama dari deret.
Dengan demikian, kita dapat mengatakan iterator bersifat malas: ketika sebuah iterator dibuat, elemennya tidak akan dihasilkan sampai diminta. Dengan kata lain, elemen-elemen dari instance list kita hanya akan dikembalikan setelah kita memintanya secara eksplisit dengan next(iter(list_instance)).
Namun, semua nilai dari sebuah iterator dapat diekstrak sekaligus dengan memanggil wadah struktur data iterable bawaan (misalnya, list(), set(), tuple()) pada objek iterator untuk memaksa iterator menghasilkan semua elemennya sekaligus.
# instantiate iterable
list_instance = [1, 2, 3, 4]
# produce an iterator from an iterable
iterator = iter(list_instance)
print(list(iterator))
"""
[1, 2, 3, 4]
"""
Ini tidak disarankan untuk iterator besar karena memaksa setiap elemen dihasilkan dan ditahan di memori sekaligus, sehingga menghilangkan manfaat evaluasi malas.
Ketika sebuah dataset terlalu besar untuk dimuat nyaman di memori, atau ketika Anda menginginkan iterasi malas tanpa menulis kelas iterator lengkap, generator biasanya lebih cocok.
Generator Python
Alternatif paling cepat untuk mengimplementasikan sebuah iterator adalah menggunakan generator. Meskipun generator terlihat seperti fungsi Python biasa, keduanya berbeda. Sebagai permulaan, objek generator tidak mengembalikan item. Sebaliknya, ia menggunakan kata kunci yield untuk menghasilkan item secara langsung saat dibutuhkan. Dengan demikian, kita dapat mengatakan generator adalah jenis fungsi khusus yang memanfaatkan evaluasi malas.
Generator tidak menyimpan isinya di memori seperti yang mungkin Anda harapkan dari sebuah iterable biasa. Sebagai contoh, jika tujuannya adalah mencari semua faktor dari sebuah bilangan bulat positif, kita biasanya akan mengimplementasikan fungsi tradisional (pelajari lebih lanjut tentang Fungsi Python dalam tutorial ini) sebagai berikut:
def factors(n):
factor_list = []
for val in range(1, n+1):
if n % val == 0:
factor_list.append(val)
return factor_list
print(factors(20))
"""
[1, 2, 4, 5, 10, 20]
"""
Kode di atas mengembalikan seluruh daftar faktor. Namun, perhatikan perbedaannya ketika sebuah generator digunakan alih-alih fungsi Python tradisional:
def factors(n):
for val in range(1, n+1):
if n % val == 0:
yield val
print(factors(20))
"""
<generator object factors at 0x7fd938271350>
"""
Karena kita menggunakan kata kunci yield alih-alih return, fungsi tidak keluar setelah berjalan. Intinya, kita memberi tahu Python untuk membuat objek generator alih-alih fungsi tradisional, yang memungkinkan status objek generator dilacak.
Akibatnya, memungkinkan untuk memanggil fungsi next() pada iterator malas tersebut untuk menampilkan elemen-elemen deret satu per satu.
def factors(n):
for val in range(1, n+1):
if n % val == 0:
yield val
factors_of_20 = factors(20)
print(next(factors_of_20))
"""
1
"""
Cara lain untuk membuat generator adalah dengan generator comprehension. Ekspresi generator mengadopsi sintaks yang mirip dengan list comprehension, kecuali menggunakan tanda kurung bulat alih-alih tanda kurung siku.
factor_gen = (val for val in range(1, 21) if 20 % val == 0)
print(list(factor_gen))
"""
[1, 2, 4, 5, 10, 20]
"""
Mengeksplorasi Kata Kunci yield di Python
Kata kunci yield mengontrol alur fungsi generator. Alih-alih keluar dari fungsi seperti saat return digunakan, kata kunci yield mengembalikan fungsi tetapi mengingat status variabel lokalnya.
Generator yang dikembalikan dari pemanggilan yield dapat diikat ke variabel dan diiterasi dengan fungsi next() – ini akan mengeksekusi fungsi hingga mencapai kata kunci yield pertama yang ditemuinya. Setelah kata kunci yield tercapai, eksekusi fungsi ditangguhkan. Ketika hal ini terjadi, status fungsi disimpan. Dengan demikian, kita dapat melanjutkan eksekusi fungsi kapan pun kita mau.
Fungsi akan berlanjut dari pemanggilan ke yield. Misalnya:
def yield_multiple_statements():
yield "This is the first statement"
yield "This is the second statement"
yield "This is the third statement"
yield "This is the last statement. Don't call next again!"
example = yield_multiple_statements()
print(next(example))
print(next(example))
print(next(example))
print(next(example))
print(next(example))
"""
This is the first statement
This is the second statement
This is the third statement
This is the last statement. Don't call next again or else!
--------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-25-4aaf9c871f91> in <module>()
11 print(next(example))
12 print(next(example))
---> 13 print(next(example))
StopIteration:
"""
Pada kode di atas, generator kita memiliki empat pemanggilan yield, tetapi kita mencoba memanggil next sebanyak lima kali, yang memunculkan pengecualian StopIteration. Perilaku ini terjadi karena generator kita bukan deret tak hingga, sehingga memanggilnya lebih banyak dari yang diharapkan akan menghabiskan generator tersebut.
Penutup
Singkatnya, iterator adalah objek yang dapat diiterasi, dan generator adalah fungsi khusus yang memanfaatkan evaluasi malas. Mengimplementasikan iterator Anda sendiri berarti Anda harus membuat metode __iter__() dan __next__(), sedangkan generator dapat diimplementasikan menggunakan kata kunci yield dalam fungsi atau comprehension Python.
Anda mungkin lebih memilih iterator kustom dibanding generator ketika Anda memerlukan objek dengan perilaku pemeliharaan status yang kompleks atau jika Anda ingin menyediakan metode lain selain __next__(), __iter__(), dan __init__(). Di sisi lain, generator mungkin lebih disukai saat menangani himpunan data besar karena mereka tidak menyimpan isinya di memori, atau ketika tidak perlu mengimplementasikan sebuah iterator.

FAQS
Apa perbedaan antara iterator dan generator di Python?
Iterator adalah objek apa pun yang mengimplementasikan __iter__() dan __next__(). Generator adalah cara yang lebih sederhana untuk membuat iterator menggunakan sebuah fungsi dengan kata kunci yield. Semua generator adalah iterator, tetapi tidak semua iterator adalah generator.
Kapan saya harus menggunakan generator alih-alih list di Python?
Gunakan generator untuk deret yang besar atau tak hingga, atau ketika efisiensi memori penting. List menahan setiap elemen sekaligus di memori, sedangkan generator menghasilkan satu nilai setiap kali. Untuk dataset kecil yang akan Anda gunakan berulang, list biasanya sudah memadai.
Apa yang dilakukan kata kunci yield di Python?
Kata kunci yield mengubah sebuah fungsi menjadi generator. Alih-alih mengembalikan dan keluar, yield menjeda fungsi, mengembalikan sebuah nilai, dan mengingat statusnya sehingga eksekusi dapat dilanjutkan pada pemanggilan berikutnya.
Bagaimana cara membuat generator di Python?
Tulislah fungsi yang menggunakan yield alih-alih return, atau gunakan ekspresi generator — sintaksnya sama seperti list comprehension tetapi dengan tanda kurung, misalnya (x * 2 for x in range(10)).
Apakah generator lebih cepat daripada iterator di Python?
Bukan dalam kecepatan mentah, tetapi generator lebih efisien memori karena menghasilkan nilai sesuai permintaan. Untuk dataset besar hal itu sering berarti performa keseluruhan yang lebih baik; untuk dataset kecil, perbedaannya bisa diabaikan.
