"Lebih mudah untuk meminta pengampunan daripada izin.": Memeriksa apakah iterator memiliki elemen selanjutnya tidak meminta izin. Ada beberapa situasi di mana Anda ingin menguji keberadaan elemen berikutnya tanpa mengkonsumsinya. Saya akan menerima solusi try catch jika ada unnext()metode untuk mengembalikan elemen pertama setelah saya memeriksa apakah ada dengan memanggil next().
Giorgio
15
@ Giorgio, tidak ada cara untuk mengetahui apakah ada elemen lain tanpa mengeksekusi kode yang menghasilkannya (Anda tidak tahu apakah generator akan mengeksekusi yieldatau tidak). Tentu saja tidak sulit untuk menulis adaptor yang menyimpan hasil next()dan menyediakan has_next()dan move_next().
avakar
5
Gagasan yang sama dapat digunakan untuk mengimplementasikan hasNext()metode (untuk menghasilkan, cache dan mengembalikan true on success, atau return false on failure). Kemudian keduanya hasNext()dan next()akan tergantung pada getNext()metode yang mendasari umum dan item di-cache. Saya benar-benar tidak mengerti mengapa next()tidak ada di perpustakaan standar jika sangat mudah untuk mengimplementasikan adaptor yang menyediakannya.
Giorgio
3
@ LarsH: Maksud Anda misalnya iterator yang membaca dari file yang dapat diubah saat membaca dari itu? Saya setuju bahwa ini bisa menjadi masalah (yang mempengaruhi penyediaan next()dan hasNext()metode pustaka , bukan hanya pustaka Python hipotetis). Jadi ya, next()dan hasNext()menjadi rumit jika konten aliran yang dipindai tergantung pada saat elemen dibaca.
Giorgio
239
Ada alternatif StopIterationdengan menggunakan next(iterator, default_value).
Untuk contoh:
>>> a = iter('hi')>>>print next(a,None)
h>>>print next(a,None)
i>>>print next(a,None)None
Jadi, Anda dapat mendeteksi Noneatau nilai yang ditentukan sebelumnya untuk akhir iterator jika Anda tidak menginginkan cara pengecualian.
jika Anda menggunakan None sebagai "sentinel", Anda sebaiknya pastikan iterator Anda tidak memiliki Nones. Anda juga bisa melakukan sentinel = object()dan next(iterator, sentinel)dan uji dengan is.
sam boosalis
1
mengikuti @samboosalis Saya lebih suka menggunakan unittest.mock.sentinelobjek bawaan yang memungkinkan Anda untuk menulis secara eksplisit next(a, sentinel.END_OF_ITERATION)dan kemudianif next(...) == sentinel.END_OF_ITERATION
ClementWalter
ini lebih cantik dari pengecualian
datdinhquoc
Masalahnya adalah, dengan cara ini, Anda MENGKONSUMSI nilai selanjutnya dari iterator juga. hasNext di Java tidak mengkonsumsi nilai berikutnya.
Alan Franzoni
39
Jika Anda benar-benar membutuhkan sebuah has-nextfungsi (karena Anda hanya setia menyalin sebuah algoritma dari implementasi referensi di Jawa, misalnya, atau karena Anda sedang menulis sebuah prototipe yang akan perlu untuk dapat dengan mudah ditranskripsi ke Jawa ketika itu selesai), mudah untuk dapatkan dengan kelas pembungkus kecil. Sebagai contoh:
x = hn_wrapper('ciao')while x.hasnext():print next(x)
memancarkan
c
i
a
o
seperti yang dipersyaratkan.
Perhatikan bahwa penggunaan next(sel.it)sebagai built-in membutuhkan Python 2.6 atau lebih baik; jika Anda menggunakan versi Python yang lebih lama, gunakan self.it.next()saja (dan juga untuk next(x)penggunaan contoh). [[Anda mungkin berpikir bahwa catatan ini berlebihan, karena Python 2.6 telah ada selama lebih dari satu tahun sekarang - tetapi lebih sering daripada tidak ketika saya menggunakan fitur Python 2.6 sebagai tanggapan, beberapa komentator atau lainnya merasa berkewajiban untuk menunjukkannya. bahwa itu adalah fitur 2.6, jadi saya mencoba untuk mencegah komentar semacam itu untuk sekali ;-)]]
"dengan setia menyalin algoritma dari implementasi referensi di Jawa" adalah alasan terburuk untuk membutuhkan suatu has_nextmetode. Desain Python tidak memungkinkan untuk, katakanlah, gunakan filteruntuk memeriksa apakah array berisi elemen yang cocok dengan predikat yang diberikan. Kesombongan dan kepicikan komunitas Python sangat mengejutkan.
Jonathan Cast
jawaban yang bagus, saya menyalin ini untuk ilustrasi beberapa pola desain yang diambil dari kode Java
madtyn
Saya dengan Python3 dan kode ini memberi sayaTypeError: iter() returned non-iterator
madtyn
1
@ JonathanCast tidak yakin saya mengikuti. Dalam Python, Anda biasanya akan menggunakan mapdan anybukannya filter, tetapi Anda bisa menggunakan SENTINEL = object(); next(filter(predicate, arr), SENTINEL) is not SENTINELatau melupakan SENTINELdan hanya menggunakan try: exceptdan menangkap StopIteration.
juanpa.arrivillaga
13
Selain semua penyebutan StopIteration, loop Python "for" hanya melakukan apa yang Anda inginkan:
>>> it = iter("hello")>>>for i in it:...print i...
h
e
l
l
o
Saya selalu bertanya-tanya mengapa di bumi python memiliki semua metode __ xxx __? Mereka tampak sangat jelek.
mP.
6
Pertanyaan yang sah! Biasanya itu sintaks untuk metode yang diekspos oleh fungsi builtin (misalnya len, sebenarnya memanggil len ). Fungsi builtin seperti itu tidak ada untuk length_hint, tetapi sebenarnya adalah proposal yang menunggu keputusan (PEP424).
fulmicoton
1
@ MP fungsi-fungsi ini ada di sana, karena kadang-kadang dibutuhkan. Mereka sengaja jelek, karena mereka dianggap sebagai metode terakhir: Jika Anda menggunakannya, Anda tahu bahwa Anda melakukan sesuatu yang non-pythonic dan berpotensi berbahaya (yang juga mungkin berhenti bekerja di titik mana pun).
Arne Babenhauserheide
Suka __init__dan __main__? Imho, ini agak berantakan tidak peduli Anda mencoba membenarkannya.
user1363990
5
hasNextagak diterjemahkan sebagai StopIterationpengecualian, misalnya:
>>> it = iter("hello")>>> it.next()'h'>>> it.next()'e'>>> it.next()'l'>>> it.next()'l'>>> it.next()'o'>>> it.next()Traceback(most recent call last):File"<stdin>", line 1,in<module>StopIteration
Kasus penggunaan yang mengarahkan saya untuk mencari ini adalah sebagai berikut
def setfrom(self,f):"""Set from iterable f"""
fi = iter(f)for i in range(self.n):try:
x = next(fi)exceptStopIteration:
fi = iter(f)
x = next(fi)
self.a[i]= x
di mana hasnext () tersedia, orang bisa melakukannya
def setfrom(self,f):"""Set from iterable f"""
fi = iter(f)for i in range(self.n):ifnot hasnext(fi):
fi = iter(f)# restart
self.a[i]= next(fi)
yang bagi saya lebih bersih. Jelas Anda dapat mengatasi masalah dengan mendefinisikan kelas utilitas, tetapi yang terjadi kemudian adalah Anda memiliki dua puluh berbagai solusi yang hampir sama dengan masing-masing dengan quirks mereka, dan jika Anda ingin menggunakan kembali kode yang menggunakan workarounds yang berbeda, Anda harus memiliki beberapa yang hampir setara dalam aplikasi tunggal Anda, atau berkeliling memilih dan menulis ulang kode untuk menggunakan pendekatan yang sama. Pepatah 'lakukan sekali dan lakukan dengan baik' gagal buruk.
Selanjutnya, iterator itu sendiri perlu memiliki pemeriksaan 'hasnext' internal untuk menjalankan untuk melihat apakah perlu memunculkan pengecualian. Pemeriksaan internal ini kemudian disembunyikan sehingga perlu diuji dengan mencoba mendapatkan item, menangkap pengecualian dan menjalankan pawang jika dilemparkan. Ini tidak perlu menyembunyikan IMO.
Untuk kasus penggunaan ini, Anda dapat menggunakan itertools.cycle
eaglebrain
0
Cara yang disarankan adalah StopIteration . Silakan lihat contoh Fibonacci dari tutorialspoint
#!usr/bin/python3import sys
def fibonacci(n):#generator function
a, b, counter =0,1,0whileTrue:if(counter > n):returnyield a
a, b = b, a + b
counter +=1
f = fibonacci(5)#f is iterator objectwhileTrue:try:print(next(f), end=" ")exceptStopIteration:
sys.exit()
Cara saya memecahkan masalah saya adalah dengan menjaga jumlah objek yang diulangi sejauh ini. Saya ingin mengulangi set menggunakan panggilan ke metode contoh. Karena saya tahu panjang set, dan jumlah item yang dihitung sejauh ini, saya secara efektif punya hasNextmetode.
Tentu saja, contohnya adalah mainan, tetapi Anda mendapatkan idenya. Ini tidak akan berfungsi dalam kasus di mana tidak ada cara untuk mendapatkan panjang iterable, seperti generator dll.
Jawaban:
Tidak, tidak ada metode seperti itu. Akhir dari iterasi ditandai dengan pengecualian. Lihat dokumentasi .
sumber
unnext()
metode untuk mengembalikan elemen pertama setelah saya memeriksa apakah ada dengan memanggilnext()
.yield
atau tidak). Tentu saja tidak sulit untuk menulis adaptor yang menyimpan hasilnext()
dan menyediakanhas_next()
danmove_next()
.hasNext()
metode (untuk menghasilkan, cache dan mengembalikan true on success, atau return false on failure). Kemudian keduanyahasNext()
dannext()
akan tergantung padagetNext()
metode yang mendasari umum dan item di-cache. Saya benar-benar tidak mengerti mengapanext()
tidak ada di perpustakaan standar jika sangat mudah untuk mengimplementasikan adaptor yang menyediakannya.next()
danhasNext()
metode pustaka , bukan hanya pustaka Python hipotetis). Jadi ya,next()
danhasNext()
menjadi rumit jika konten aliran yang dipindai tergantung pada saat elemen dibaca.Ada alternatif
StopIteration
dengan menggunakannext(iterator, default_value)
.Untuk contoh:
Jadi, Anda dapat mendeteksi
None
atau nilai yang ditentukan sebelumnya untuk akhir iterator jika Anda tidak menginginkan cara pengecualian.sumber
sentinel = object()
dannext(iterator, sentinel)
dan uji denganis
.unittest.mock.sentinel
objek bawaan yang memungkinkan Anda untuk menulis secara eksplisitnext(a, sentinel.END_OF_ITERATION)
dan kemudianif next(...) == sentinel.END_OF_ITERATION
Jika Anda benar-benar membutuhkan sebuah
has-next
fungsi (karena Anda hanya setia menyalin sebuah algoritma dari implementasi referensi di Jawa, misalnya, atau karena Anda sedang menulis sebuah prototipe yang akan perlu untuk dapat dengan mudah ditranskripsi ke Jawa ketika itu selesai), mudah untuk dapatkan dengan kelas pembungkus kecil. Sebagai contoh:sekarang sesuatu seperti
memancarkan
seperti yang dipersyaratkan.
Perhatikan bahwa penggunaan
next(sel.it)
sebagai built-in membutuhkan Python 2.6 atau lebih baik; jika Anda menggunakan versi Python yang lebih lama, gunakanself.it.next()
saja (dan juga untuknext(x)
penggunaan contoh). [[Anda mungkin berpikir bahwa catatan ini berlebihan, karena Python 2.6 telah ada selama lebih dari satu tahun sekarang - tetapi lebih sering daripada tidak ketika saya menggunakan fitur Python 2.6 sebagai tanggapan, beberapa komentator atau lainnya merasa berkewajiban untuk menunjukkannya. bahwa itu adalah fitur 2.6, jadi saya mencoba untuk mencegah komentar semacam itu untuk sekali ;-)]]sumber
has_next
metode. Desain Python tidak memungkinkan untuk, katakanlah, gunakanfilter
untuk memeriksa apakah array berisi elemen yang cocok dengan predikat yang diberikan. Kesombongan dan kepicikan komunitas Python sangat mengejutkan.TypeError: iter() returned non-iterator
map
danany
bukannyafilter
, tetapi Anda bisa menggunakanSENTINEL = object(); next(filter(predicate, arr), SENTINEL) is not SENTINEL
atau melupakanSENTINEL
dan hanya menggunakantry: except
dan menangkapStopIteration
.Selain semua penyebutan StopIteration, loop Python "for" hanya melakukan apa yang Anda inginkan:
sumber
Coba metode __length_hint __ () dari objek iterator apa pun:
sumber
__init__
dan__main__
? Imho, ini agak berantakan tidak peduli Anda mencoba membenarkannya.hasNext
agak diterjemahkan sebagaiStopIteration
pengecualian, misalnya:StopIteration
docs: http://docs.python.org/library/exceptions.html#exceptions.StopIterationsumber
Anda dapat
tee
menggunakan iteratoritertools.tee
,, dan memeriksaStopIteration
iterator yang diolah.sumber
Tidak. Konsep yang paling mirip adalah pengecualian StopIteration.
sumber
Saya percaya python hanya memiliki next () dan menurut doc, ada pengecualian adalah tidak ada elemen lagi.
http://docs.python.org/library/stdtypes.html#iterator-types
sumber
Kasus penggunaan yang mengarahkan saya untuk mencari ini adalah sebagai berikut
di mana hasnext () tersedia, orang bisa melakukannya
yang bagi saya lebih bersih. Jelas Anda dapat mengatasi masalah dengan mendefinisikan kelas utilitas, tetapi yang terjadi kemudian adalah Anda memiliki dua puluh berbagai solusi yang hampir sama dengan masing-masing dengan quirks mereka, dan jika Anda ingin menggunakan kembali kode yang menggunakan workarounds yang berbeda, Anda harus memiliki beberapa yang hampir setara dalam aplikasi tunggal Anda, atau berkeliling memilih dan menulis ulang kode untuk menggunakan pendekatan yang sama. Pepatah 'lakukan sekali dan lakukan dengan baik' gagal buruk.
Selanjutnya, iterator itu sendiri perlu memiliki pemeriksaan 'hasnext' internal untuk menjalankan untuk melihat apakah perlu memunculkan pengecualian. Pemeriksaan internal ini kemudian disembunyikan sehingga perlu diuji dengan mencoba mendapatkan item, menangkap pengecualian dan menjalankan pawang jika dilemparkan. Ini tidak perlu menyembunyikan IMO.
sumber
Cara yang disarankan adalah StopIteration . Silakan lihat contoh Fibonacci dari tutorialspoint
sumber
Cara saya memecahkan masalah saya adalah dengan menjaga jumlah objek yang diulangi sejauh ini. Saya ingin mengulangi set menggunakan panggilan ke metode contoh. Karena saya tahu panjang set, dan jumlah item yang dihitung sejauh ini, saya secara efektif punya
hasNext
metode.Versi sederhana dari kode saya:
Tentu saja, contohnya adalah mainan, tetapi Anda mendapatkan idenya. Ini tidak akan berfungsi dalam kasus di mana tidak ada cara untuk mendapatkan panjang iterable, seperti generator dll.
sumber