Apa perbedaan antara iterator dan generator? Beberapa contoh kapan Anda akan menggunakan setiap kasing akan sangat membantu.
Apa perbedaan antara iterator dan generator? Beberapa contoh kapan Anda akan menggunakan setiap kasing akan sangat membantu.
Jawaban:
iterator
adalah konsep yang lebih umum: objek apa pun yang kelasnya memiliki next
metode ( __next__
dengan Python 3) dan __iter__
metode yang melakukannya return self
.
Setiap generator adalah iterator, tetapi tidak sebaliknya. Generator dibangun dengan memanggil fungsi yang memiliki satu atau lebih yield
ekspresi ( yield
pernyataan, dalam Python 2.5 dan sebelumnya), dan merupakan objek yang memenuhi definisi paragraf sebelumnya tentang suatu iterator
.
Anda mungkin ingin menggunakan iterator khusus, bukan generator, ketika Anda membutuhkan kelas dengan perilaku pemeliharaan keadaan yang agak rumit, atau ingin mengekspos metode lain selain next
(dan __iter__
dan __init__
). Paling sering, generator (kadang-kadang, untuk kebutuhan yang cukup sederhana, ekspresi generator ) cukup, dan lebih mudah untuk dikodekan karena pemeliharaan negara (dalam batas yang wajar) pada dasarnya "dilakukan untuk Anda" oleh frame yang ditangguhkan dan dilanjutkan.
Misalnya, generator seperti:
def squares(start, stop):
for i in range(start, stop):
yield i * i
generator = squares(a, b)
atau ekspresi generator yang setara (genexp)
generator = (i*i for i in range(a, b))
akan membutuhkan lebih banyak kode untuk dibuat sebagai iterator khusus:
class Squares(object):
def __init__(self, start, stop):
self.start = start
self.stop = stop
def __iter__(self): return self
def next(self): # __next__ in Python 3
if self.start >= self.stop:
raise StopIteration
current = self.start * self.start
self.start += 1
return current
iterator = Squares(a, b)
Tetapi, tentu saja, dengan kelas Squares
Anda dapat dengan mudah menawarkan metode tambahan, yaitu
def current(self):
return self.start
jika Anda benar-benar membutuhkan fungsionalitas ekstra dalam aplikasi Anda.
for ... in ...:
, diteruskan ke fungsi, atau Anda akan meneleponiter.next()
for..in
sintaks. Mungkin saya kehilangan sesuatu, tetapi beberapa waktu yang lalu, saya tidak ingat jika saya menyelesaikannya. Terima kasih!
Apa perbedaan antara iterator dan generator? Beberapa contoh kapan Anda akan menggunakan setiap kasing akan sangat membantu.
Singkatnya: Iterator adalah objek yang memiliki metode __iter__
and __next__
( next
in Python 2). Generator menyediakan cara bawaan yang mudah untuk membuat instance dari Iterators.
Fungsi dengan hasil di dalamnya masih merupakan fungsi, yang, ketika dipanggil, mengembalikan turunan objek generator:
def a_function():
"when called, returns generator object"
yield
Ekspresi generator juga mengembalikan generator:
a_generator = (i for i in range(0))
Untuk eksposisi dan contoh yang lebih mendalam, teruslah membaca.
Secara khusus, generator adalah subtipe dari iterator.
>>> import collections, types
>>> issubclass(types.GeneratorType, collections.Iterator)
True
Kita dapat membuat generator dengan beberapa cara. Cara yang sangat umum dan sederhana untuk melakukannya adalah dengan suatu fungsi.
Secara khusus, fungsi dengan hasil di dalamnya adalah fungsi, yang ketika dipanggil, mengembalikan generator:
>>> def a_function():
"just a function definition with yield in it"
yield
>>> type(a_function)
<class 'function'>
>>> a_generator = a_function() # when called
>>> type(a_generator) # returns a generator
<class 'generator'>
Dan generator, sekali lagi, adalah Iterator:
>>> isinstance(a_generator, collections.Iterator)
True
Iterator adalah Iterable,
>>> issubclass(collections.Iterator, collections.Iterable)
True
yang membutuhkan __iter__
metode yang mengembalikan Iterator:
>>> collections.Iterable()
Traceback (most recent call last):
File "<pyshell#79>", line 1, in <module>
collections.Iterable()
TypeError: Can't instantiate abstract class Iterable with abstract methods __iter__
Beberapa contoh iterables adalah built-in tuple, daftar, kamus, set, set beku, string, byte string, byte array, range dan memoryviews:
>>> all(isinstance(element, collections.Iterable) for element in (
(), [], {}, set(), frozenset(), '', b'', bytearray(), range(0), memoryview(b'')))
True
next
atau a__next__
Dengan Python 2:
>>> collections.Iterator()
Traceback (most recent call last):
File "<pyshell#80>", line 1, in <module>
collections.Iterator()
TypeError: Can't instantiate abstract class Iterator with abstract methods next
Dan dengan Python 3:
>>> collections.Iterator()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Iterator with abstract methods __next__
Kita bisa mendapatkan iterator dari objek bawaan (atau objek khusus) dengan iter
fungsi:
>>> all(isinstance(iter(element), collections.Iterator) for element in (
(), [], {}, set(), frozenset(), '', b'', bytearray(), range(0), memoryview(b'')))
True
The __iter__
metode ini disebut ketika Anda mencoba untuk menggunakan objek dengan untuk loop. Kemudian __next__
metode ini dipanggil pada objek iterator untuk mendapatkan setiap item untuk loop. Iterator muncul StopIteration
ketika Anda telah kehabisan, dan itu tidak dapat digunakan kembali pada saat itu.
Dari bagian Generator Type dari bagian Tipe Iterator dari dokumentasi Built-in Type :
Generator Python menyediakan cara yang nyaman untuk mengimplementasikan protokol iterator. Jika
__iter__()
metode objek kontainer diimplementasikan sebagai generator, itu akan secara otomatis mengembalikan objek iterator (secara teknis, objek generator) memasok metode__iter__()
dannext()
[__next__()
dengan Python 3]. Informasi lebih lanjut tentang generator dapat ditemukan dalam dokumentasi untuk ekspresi hasil.
(Penekanan ditambahkan.)
Jadi dari sini kita belajar bahwa Generator adalah jenis Iterator (nyaman).
Anda dapat membuat objek yang mengimplementasikan protokol Iterator dengan membuat atau memperluas objek Anda sendiri.
class Yes(collections.Iterator):
def __init__(self, stop):
self.x = 0
self.stop = stop
def __iter__(self):
return self
def next(self):
if self.x < self.stop:
self.x += 1
return 'yes'
else:
# Iterators must raise when done, else considered broken
raise StopIteration
__next__ = next # Python 3 compatibility
Tetapi lebih mudah menggunakan Generator untuk melakukan ini:
def yes(stop):
for _ in range(stop):
yield 'yes'
Atau mungkin lebih sederhana, Ekspresi Generator (bekerja serupa dengan daftar pemahaman):
yes_expr = ('yes' for _ in range(stop))
Semua itu dapat digunakan dengan cara yang sama:
>>> stop = 4
>>> for i, y1, y2, y3 in zip(range(stop), Yes(stop), yes(stop),
('yes' for _ in range(stop))):
... print('{0}: {1} == {2} == {3}'.format(i, y1, y2, y3))
...
0: yes == yes == yes
1: yes == yes == yes
2: yes == yes == yes
3: yes == yes == yes
Anda dapat menggunakan protokol Iterator secara langsung ketika Anda perlu memperluas objek Python sebagai objek yang dapat diulangi.
Namun, dalam sebagian besar kasus, Anda paling cocok digunakan yield
untuk mendefinisikan fungsi yang mengembalikan Generator Iterator atau mempertimbangkan Ekspresi Generator.
Akhirnya, perhatikan bahwa generator menyediakan fungsionalitas lebih sebagai coroutine. Saya menjelaskan Generator, bersama dengan yield
pernyataan, secara mendalam pada jawaban saya untuk "Apa kata kunci" hasil "lakukan?".
Iterator:
Iterator adalah objek yang menggunakan next()
metode untuk mendapatkan nilai urutan berikutnya.
Generator:
Generator adalah fungsi yang menghasilkan atau menghasilkan urutan nilai menggunakan yield
metode.
Setiap next()
panggilan metode pada objek generator (untuk contoh: f
seperti dalam contoh di bawah ini) dikembalikan oleh fungsi generator (misalnya: foo()
fungsi dalam contoh di bawah), menghasilkan nilai berikutnya secara berurutan.
Ketika fungsi generator dipanggil, ia mengembalikan objek generator bahkan tanpa memulai eksekusi fungsi. Ketika next()
metode dipanggil untuk pertama kalinya, fungsi mulai mengeksekusi sampai mencapai pernyataan hasil yang mengembalikan nilai yang dihasilkan. Hasil melacak yaitu mengingat eksekusi terakhir. Dan next()
panggilan kedua berlanjut dari nilai sebelumnya.
Contoh berikut menunjukkan interaksi antara hasil dan panggilan ke metode selanjutnya pada objek generator.
>>> def foo():
... print "begin"
... for i in range(3):
... print "before yield", i
... yield i
... print "after yield", i
... print "end"
...
>>> f = foo()
>>> f.next()
begin
before yield 0 # Control is in for loop
0
>>> f.next()
after yield 0
before yield 1 # Continue for loop
1
>>> f.next()
after yield 1
before yield 2
2
>>> f.next()
after yield 2
end
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
Menambahkan jawaban karena tidak ada jawaban yang ada yang secara khusus mengatasi kebingungan dalam literatur resmi.
Fungsi generator adalah fungsi biasa yang didefinisikan menggunakanyield
alih-alihreturn
. Ketika dipanggil, fungsi generator mengembalikan objek generator , yang merupakan sejenis iterator - ia memilikinext()
metode. Saat Anda meneleponnext()
, nilai selanjutnya yang dihasilkan oleh fungsi generator dikembalikan.
Baik fungsi atau objek dapat disebut "generator" tergantung pada dokumen sumber Python yang Anda baca. Daftar istilah Python mengatakan fungsi generator, sedangkan wiki Python menyiratkan objek generator. The Python tutorial sangat berhasil menyiratkan baik penggunaan di ruang tiga kalimat:
Generator adalah alat sederhana dan kuat untuk membuat iterator. Mereka ditulis seperti fungsi biasa tetapi menggunakan pernyataan hasil setiap kali mereka ingin mengembalikan data. Setiap kali next () dipanggil, generator melanjutkan di tempat yang ditinggalkannya (ia mengingat semua nilai data dan pernyataan mana yang terakhir dieksekusi).
Dua kalimat pertama mengidentifikasi generator dengan fungsi generator, sedangkan kalimat ketiga mengidentifikasi mereka dengan objek generator.
Terlepas dari semua kebingungan ini, orang dapat mencari referensi bahasa Python untuk kata yang jelas dan terakhir:
Ekspresi hasil hanya digunakan ketika mendefinisikan fungsi generator, dan hanya dapat digunakan dalam tubuh definisi fungsi. Menggunakan ekspresi hasil dalam definisi fungsi sudah cukup untuk menyebabkan definisi itu untuk membuat fungsi generator, bukan fungsi normal.
Ketika fungsi generator dipanggil, ia mengembalikan iterator yang dikenal sebagai generator. Generator itu kemudian mengontrol pelaksanaan fungsi generator.
Jadi, dalam penggunaan formal dan tepat, "generator" tidak memenuhi syarat berarti objek generator, bukan fungsi generator.
Referensi di atas adalah untuk Python 2 tetapi referensi bahasa Python 3 mengatakan hal yang sama. Namun, daftar istilah Python 3 menyatakan itu
generator ... Biasanya mengacu pada fungsi generator, tetapi dapat merujuk ke generator iterator dalam beberapa konteks. Dalam kasus di mana makna yang dimaksudkan tidak jelas, menggunakan istilah lengkap menghindari ambiguitas.
Semua orang memiliki jawaban yang sangat bagus dan jelas dengan contoh-contoh dan saya sangat menghargainya. Saya hanya ingin memberikan jawaban singkat untuk orang-orang yang secara konsep masih belum jelas:
Jika Anda membuat iterator Anda sendiri, ini sedikit terlibat - Anda harus membuat kelas dan setidaknya mengimplementasikan iter dan metode selanjutnya. Tetapi bagaimana jika Anda tidak ingin melalui kerumitan ini dan ingin cepat membuat iterator. Untungnya, Python menyediakan cara pintas untuk mendefinisikan iterator. Yang perlu Anda lakukan adalah mendefinisikan fungsi dengan setidaknya 1 panggilan untuk menghasilkan dan sekarang ketika Anda memanggil fungsi itu akan mengembalikan " sesuatu " yang akan bertindak seperti iterator (Anda dapat memanggil metode selanjutnya dan menggunakannya dalam for loop). Sesuatu ini memiliki nama dalam Python yang disebut Generator
Harapan itu sedikit memperjelas.
Jawaban sebelumnya melewatkan penambahan ini: generator memiliki close
metode, sedangkan iterator tipikal tidak. The close
Metode pemicu sebuah StopIteration
pengecualian dalam generator, yang mungkin terjebak dalam finally
klausul dalam iterator itu, untuk mendapatkan kesempatan untuk menjalankan beberapa bersih-bersih. Abstraksi ini membuatnya paling bisa digunakan dalam iterator besar daripada sederhana. Orang dapat menutup generator seperti orang dapat menutup file, tanpa harus repot dengan apa yang ada di bawahnya.
Yang mengatakan, jawaban pribadi saya untuk pertanyaan pertama adalah: iteratable hanya memiliki __iter__
metode, iterators khas hanya memiliki __next__
metode, generator memiliki kedua __iter__
dan satu __next__
dan tambahan close
.
Untuk pertanyaan kedua, jawaban pribadi saya adalah: di antarmuka publik, saya cenderung lebih menyukai generator, karena lebih tangguh: close
metode yang komposisinya lebih besar yield from
. Secara lokal, saya dapat menggunakan iterator, tetapi hanya jika itu adalah struktur datar dan sederhana (iterator tidak mudah dikomposisi) dan jika ada alasan untuk percaya urutannya agak pendek terutama jika dapat dihentikan sebelum mencapai akhir. Saya cenderung memandang iterator sebagai primitif tingkat rendah, kecuali sebagai literal.
Untuk masalah aliran kontrol, generator adalah konsep yang sama pentingnya dengan janji: keduanya abstrak dan dapat disusun.
__iter__
metode, bagaimana bisa iterator __next__
hanya memiliki ? Jika mereka seharusnya iterables, saya harapkan mereka __iter__
juga harus begitu.
__iter__
on iterables untuk mengembalikan iterator, yang hanya membutuhkan next
metode ( __next__
dalam Python3). Tolong jangan bingung standar (untuk mengetik bebek) dengan implementasinya (bagaimana juru bahasa Python tertentu menerapkannya). Ini agak seperti kebingungan antara fungsi generator (definisi) dan objek generator (implementasi). ;)
Fungsi Generator, Objek Generator, Generator:
Sebuah fungsi Generator adalah seperti fungsi biasa dengan Python tapi mengandung satu atau lebih yield
pernyataan. Fungsi generator adalah alat yang hebat untuk membuat objek Iterator semudah mungkin. The Iterator objek returend oleh function generator juga disebut objek Generator atau Generator .
Dalam contoh ini saya telah membuat fungsi Generator yang mengembalikan objek Generator <generator object fib at 0x01342480>
. Sama seperti iterator lainnya, objek Generator dapat digunakan dalam satu for
lingkaran atau dengan fungsi next()
bawaan yang mengembalikan nilai berikutnya dari generator.
def fib(max):
a, b = 0, 1
for i in range(max):
yield a
a, b = b, a + b
print(fib(10)) #<generator object fib at 0x01342480>
for i in fib(10):
print(i) # 0 1 1 2 3 5 8 13 21 34
print(next(myfib)) #0
print(next(myfib)) #1
print(next(myfib)) #1
print(next(myfib)) #2
Jadi fungsi generator adalah cara termudah untuk membuat objek Iterator.
Iterator :
Setiap objek generator adalah iterator tetapi tidak sebaliknya. Objek iterator kustom dapat dibuat jika kelasnya mengimplementasikan __iter__
dan __next__
metode (juga disebut protokol iterator).
Namun, jauh lebih mudah untuk menggunakan fungsi generator untuk membuat iterator karena mereka menyederhanakan pembuatannya, tetapi Iterator khusus memberi Anda lebih banyak kebebasan dan Anda juga dapat menerapkan metode lain sesuai dengan kebutuhan Anda seperti yang ditunjukkan pada contoh di bawah ini.
class Fib:
def __init__(self,max):
self.current=0
self.next=1
self.max=max
self.count=0
def __iter__(self):
return self
def __next__(self):
if self.count>self.max:
raise StopIteration
else:
self.current,self.next=self.next,(self.current+self.next)
self.count+=1
return self.next-self.current
def __str__(self):
return "Generator object"
itobj=Fib(4)
print(itobj) #Generator object
for i in Fib(4):
print(i) #0 1 1 2
print(next(itobj)) #0
print(next(itobj)) #1
print(next(itobj)) #1
Contoh dari Ned Batchelder sangat direkomendasikan untuk iterator dan generator
Sebuah metode tanpa generator yang melakukan sesuatu ke angka genap
def evens(stream):
them = []
for n in stream:
if n % 2 == 0:
them.append(n)
return them
sementara dengan menggunakan generator
def evens(stream):
for n in stream:
if n % 2 == 0:
yield n
return
pernyataanMemanggil evens
metode (generator) seperti biasa
num = [...]
for n in evens(num):
do_smth(n)
Iterator
Buku yang penuh halaman adalah iterable , bookmark adalah iterator
dan bookmark ini tidak ada hubungannya kecuali bergerak next
litr = iter([1,2,3])
next(litr) ## 1
next(litr) ## 2
next(litr) ## 3
next(litr) ## StopIteration (Exception) as we got end of the iterator
Untuk menggunakan Generator ... kita membutuhkan suatu fungsi
Untuk menggunakan Iterator ... kita perlu next
daniter
Seperti yang dikatakan:
Fungsi Generator mengembalikan objek iterator
Manfaat Seluruh Iterator:
Simpan satu elemen setiap kali dalam memori
Anda dapat membandingkan kedua pendekatan untuk data yang sama:
def myGeneratorList(n):
for i in range(n):
yield i
def myIterableList(n):
ll = n*[None]
for i in range(n):
ll[i] = i
return ll
# Same values
ll1 = myGeneratorList(10)
ll2 = myIterableList(10)
for i1, i2 in zip(ll1, ll2):
print("{} {}".format(i1, i2))
# Generator can only be read once
ll1 = myGeneratorList(10)
ll2 = myIterableList(10)
print("{} {}".format(len(list(ll1)), len(ll2)))
print("{} {}".format(len(list(ll1)), len(ll2)))
# Generator can be read several times if converted into iterable
ll1 = list(myGeneratorList(10))
ll2 = myIterableList(10)
print("{} {}".format(len(list(ll1)), len(ll2)))
print("{} {}".format(len(list(ll1)), len(ll2)))
Selain itu, jika Anda memeriksa jejak memori, generator mengambil lebih sedikit memori karena tidak perlu menyimpan semua nilai dalam memori secara bersamaan.
Saya menulis khusus untuk pemula Python dengan cara yang sangat sederhana, meskipun jauh di lubuk hati Python melakukan banyak hal.
Mari kita mulai dengan yang paling mendasar:
Pertimbangkan daftar,
l = [1,2,3]
Mari kita menulis fungsi yang setara:
def f():
return [1,2,3]
o / p dari print(l): [1,2,3]
& o / p dariprint(f()) : [1,2,3]
Mari kita buat daftar l iterable: Dalam daftar python selalu iterable yang berarti Anda dapat menerapkan iterator kapan pun Anda inginkan.
Mari kita terapkan iterator pada daftar:
iter_l = iter(l) # iterator applied explicitly
Mari kita membuat fungsi yang dapat diubah, yaitu menulis fungsi generator yang setara.
Dengan python segera setelah Anda memasukkan kata kunci yield
; itu menjadi fungsi generator dan iterator akan diterapkan secara implisit.
Catatan: Setiap generator selalu iterable dengan iterator implisit diterapkan dan di sini iterator implisit adalah yang terpenting Jadi fungsi generator adalah:
def f():
yield 1
yield 2
yield 3
iter_f = f() # which is iter(f) as iterator is already applied implicitly
Jadi jika Anda telah mengamati, segera setelah Anda membuat generator fungsi fa, itu sudah iter (f)
Sekarang,
l adalah daftar, setelah menerapkan metode iterator "iter" menjadi, iter (l)
f sudah iter (f), setelah menerapkan metode iterator "iter" menjadi, iter (iter (f)), yang lagi-lagi iter (f)
Ini agaknya Anda casting int ke int (x) yang sudah int dan itu akan tetap int (x).
Misalnya o / p dari:
print(type(iter(iter(l))))
adalah
<class 'list_iterator'>
Jangan pernah lupa ini adalah Python dan bukan C atau C ++
Maka kesimpulan dari penjelasan di atas adalah:
daftar l ~ = iter (l)
fungsi generator f == iter (f)