Perilaku daftar iterator python dan selanjutnya (iterator)

147

Mempertimbangkan:

>>> lst = iter([1,2,3])
>>> next(lst)
1
>>> next(lst)
2

Jadi, memajukan iterator, seperti yang diharapkan, ditangani dengan memutasi objek yang sama.

Karena itu, saya berharap:

a = iter(list(range(10)))
for i in a:
   print(i)
   next(a)

untuk melewati setiap elemen kedua: panggilan ke nextharus memajukan iterator sekali, maka panggilan implisit yang dibuat oleh loop harus memajukannya untuk kedua kalinya - dan hasil panggilan kedua ini akan ditugaskan untuk i.

Tidak. Lingkaran mencetak semua item dalam daftar, tanpa melewatkan apapun.

Pikiran pertama saya adalah bahwa ini mungkin terjadi karena loop memanggil iterapa yang dilewati, dan ini mungkin memberikan iterator independen - ini bukan masalahnya, seperti yang kita miliki iter(a) is a.

Jadi, mengapa nexttidak muncul untuk memajukan iterator dalam kasus ini?

lvc
sumber

Jawaban:

197

Apa yang Anda lihat adalah penerjemah menggemakan kembali nilai kembali next()selain idicetak setiap iterasi:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    next(a)
... 
0
1
2
3
4
5
6
7
8
9

Begitu 0juga dengan output print(i), 1nilai pengembalian dari next(), digemakan oleh interpreter interaktif, dll. Hanya ada 5 iterasi, setiap iterasi menghasilkan 2 baris yang ditulis ke terminal.

Jika Anda menetapkan output next()hal - hal berfungsi seperti yang diharapkan:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    _ = next(a)
... 
0
2
4
6
8

atau cetak informasi tambahan untuk membedakan print()output dari gema interpreter interaktif:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print('Printing: {}'.format(i))
...    next(a)
... 
Printing: 0
1
Printing: 2
3
Printing: 4
5
Printing: 6
7
Printing: 8
9

Dengan kata lain, next()berfungsi seperti yang diharapkan, tetapi karena mengembalikan nilai berikutnya dari iterator, yang digaungkan oleh interpreter interaktif, Anda dituntun untuk percaya bahwa loop memiliki salinan iterator sendiri.

Martijn Pieters
sumber
13
Saya tidak mengetahui perilaku ini dari penerjemah. Saya senang bahwa saya menemukan itu sebelum kehilangan banyak waktu bertanya-tanya tentang hal itu sambil menyelesaikan beberapa masalah nyata.
brandizzi
5
... * mati *. Yang terburuk adalah, saya bisa ingat menyebutkan persis perilaku juru bahasa ini kepada seseorang mungkin seminggu yang lalu.
Lvc
menarik. Saya mencoba untuk saya di: selanjutnya (a); cetak saya dan saya pikir saya akan melompat ke 1 dan mencetak 1,3,5,7,9. Tapi tetap saja 0,2,4,6,8. Mengapa?
user2290820
3
iitu sudah ditetapkan. next(a)berarti bahwa iterasi berikutnya 2ditugaskan i, kemudian Anda bergerak alagi, mencetak i, dll.
Martijn Pieters
1
Ini tidak berfungsi jika n ganjil - StopIterationexcepetio nis dinaikkan ketika next(a)dipanggil setelah daftar habis.
Raf
13

Apa yang terjadi adalah yang next(a)mengembalikan nilai berikutnya dari a, yang dicetak ke konsol karena tidak terpengaruh.

Apa yang dapat Anda lakukan adalah memengaruhi variabel dengan nilai ini:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    b=next(a)
...
0
2
4
6
8
njzk2
sumber
8

Saya menemukan jawaban yang ada sedikit membingungkan, karena mereka hanya secara tidak langsung menunjukkan hal membingungkan yang penting dalam contoh kode: keduanya * "print i" dan "next (a)" menyebabkan hasil mereka dicetak.

Karena mereka mencetak elemen bergantian dari urutan asli, dan tidak terduga bahwa pernyataan "selanjutnya (a)" dicetak, tampak seolah-olah pernyataan "cetak saya" mencetak semua nilai.

Dalam terang itu, menjadi lebih jelas bahwa menetapkan hasil "next (a)" ke suatu variabel menghambat pencetakan hasilnya, sehingga hanya nilai-nilai alternatif yang dicetak oleh variabel loop "i". Demikian pula, membuat pernyataan "cetak" mengeluarkan sesuatu yang lebih khas juga melemahkannya.

(Salah satu jawaban yang ada membantah yang lain karena jawaban itu memiliki kode contoh dievaluasi sebagai blok, sehingga penerjemah tidak melaporkan nilai antara untuk "selanjutnya (a)".)

Hal yang menarik dalam menjawab pertanyaan, secara umum, adalah eksplisit tentang apa yang jelas setelah Anda tahu jawabannya. Itu bisa sulit dipahami. Demikian juga mengkritik jawaban setelah Anda memahaminya. Ini menarik...

klm
sumber
2

Ada yang salah dengan Python / Komputer Anda.

a = iter(list(range(10)))
for i in a:
   print(i)
   next(a)

>>> 
0
2
4
6
8

Bekerja seperti yang diharapkan.

Diuji dalam Python 2.7 dan Python 3+. Bekerja dengan baik di keduanya

Inbar Rose
sumber
5
Saya mendapatkan hasil yang sama dengan @lvc (hanya pada IDLE namun, ketika dieksekusi sebagai skrip saya mendapatkan ini))
jamylak
3
@Inbar Rose Hanya jika Anda menjalankan sebagai skrip.
Quintec
1
itu adalah perilaku menempatkan kode melalui shell interaktif. Jika fungsi mengembalikan nilai tanpa digunakan, interpreter akan mencetaknya ke shell sebagai hasil debug
Reishin
2

Bagi yang masih belum mengerti.

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    next(a)
... 
0 # print(i) printed this
1 # next(a) printed this
2 # print(i) printed this
3 # next(a) printed this
4 # print(i) printed this
5 # next(a) printed this
6 # print(i) printed this
7 # next(a) printed this
8 # print(i) printed this
9 # next(a) printed this

Seperti yang telah dikatakan orang lain, nexttingkatkan iterator sebesar 1 seperti yang diharapkan. Menetapkan nilai yang dikembalikan ke variabel tidak secara ajaib mengubah perilakunya.

Wesley
sumber
1

Itu berperilaku seperti yang Anda inginkan jika dipanggil sebagai fungsi:

>>> def test():
...     a = iter(list(range(10)))
...     for i in a:
...         print(i)
...         next(a)
... 
>>> test()
0
2
4
6
8
Burmer
sumber