Python listesi yineleyici davranışı ve sonraki (yineleyici)


147

Düşünmek:

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

Dolayısıyla, yineleyicinin ilerletilmesi, beklendiği gibi, aynı nesneyi değiştirerek ele alınır.

Bu durumda, ben beklenir:

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

her ikinci öğeyi atlamak için: çağrıyı nextyineleyiciyi bir kez ilerletmeli, sonra döngü tarafından yapılan örtülü çağrı onu ikinci kez ilerletmelidir - ve bu ikinci çağrının sonucu atanır i.

Öyle değil. Döngü , listedeki tüm öğeleri, hiçbirini atlamadan yazdırır .

İlk düşüncem bunun olabileceğiydi, çünkü döngü geçileni çağırıyor iterve bu bağımsız bir yineleyici verebilir - bizim durumumuz böyle değil iter(a) is a.

Peki, neden nextbu durumda yineleyiciyi ilerletmiyor?

Yanıtlar:


197

Gördüğünüz şey, her yinelemeyi yazdırmanın yanı sıra , dönüş değerini geri yansıtan yorumlayıcıdır :next()i

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

Yani 0çıktısıdır print(i), 1dönüş değerinext() 2 hatlarında sonuçlanan her yineleme terminaline yazılırken, sadece 5 iterasyon vardır interaktif yorumlayıcı tarafından yankılandı, vb.

next()İşlerin çıktısını beklendiği gibi atarsanız :

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

ya da çıktıyı etkileşimli yorumlayıcı yankısından ayırt etmek için ek bilgiler yazdırın print():

>>> 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

Başka bir deyişle, next()beklendiği gibi çalışıyor, ancak etkileşimli yorumlayıcı tarafından yinelenen yineleyiciden sonraki değeri döndürdüğü için, döngünün bir şekilde kendi yineleyici kopyasına sahip olduğuna inanmaya yönlendirilirsiniz.


13
Tercümanın bu davranışının farkında değildim. Gerçek bir problemi çözerken çok fazla zaman kaybetmeden merak ettiğimi keşfettiğim için memnunum.
brandizzi

5
... * ölür *. En kötüsü, belki de bir hafta önce birisine bu tercüman davranışından bahsettiğimi hatırlıyorum.
lvc

ilginç. Ben i için denedim: sonraki (a); baskı i ve ben 1 atlamak ve 1,3,5,7,9 yazdırmak düşündüm. Ama yine de 0,2,4,6,8. Neden?
user2290820

3
ioldu zaten atanmış. next(a)bir sonraki yinelemenin 2atandığı anlamına gelir i, o zaman atekrar ilerler, yazdırır i, vb.
Martijn Pieters

1
N tuhafsa bu işe yaramaz - StopIteration tuhafsanext(a) liste kaldırıldıktan sonra çağrıldığında istisna kaldırılır .
Raf

13

Olan şu ki next(a) etkilenmediği için konsola yazdırılan bir sonraki a değerini döndürmesidir.

Yapabileceğiniz şey bu değere sahip bir değişkeni etkilemektir:

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

8

Mevcut cevapları biraz kafa karıştırıcı buluyorum, çünkü sadece dolaylı olarak kod örneğinde temel gizemli şeyi gösteriyorlar: her ikisi de * "print i" hem de "next (a)" sonuçlarının yazdırılmasına neden oluyorlar.

Orijinal dizinin alternatif öğelerini yazdırdıkları ve "next (a)" ifadesinin yazdırıldığı beklenmedik olduğundan, "print i" ifadesi tüm değerleri yazdırıyor gibi görünüyor.

Bu ışık altında, bir değişkene "next (a)" sonucunun atanmasının, sonucunun yazdırılmasını engellediği ve böylece "i" döngü değişkeninin yazdırıldığı alternatif değerlerin yazdırıldığı daha açık hale gelir. Benzer şekilde, "print" ifadesinin daha belirgin bir şey yayınlaması da onu belirginleştiriyor.

(Mevcut cevaplardan biri diğerlerini çürütür, çünkü bu cevap örnek kodun bir blok olarak değerlendirilmesini sağlamaktır, böylece yorumlayıcı "sonraki (a)" için ara değerleri raporlamamaktadır.)

Genel olarak soruları yanıtlamanın en uyandırıcı yanı, cevabı öğrendikten sonra neyin açık olduğunun açık olmasıdır. Zor olabilir. Aynı şekilde cevapları anladıktan sonra eleştirmek. İlginç...


2

Python / Bilgisayarınızla ilgili bir sorun var.

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

>>> 
0
2
4
6
8

Beklendiği gibi çalışır.

Python 2.7 ve Python 3+ 'da test edilmiştir. Her ikisinde de düzgün çalışır


5
@Lvc ile aynı sonucu alıyorum (sadece IDLE'de ancak komut dosyası olarak çalıştırıldığında bunu alıyorum))
Jamylak

3
@Inbar Rose Yalnızca komut dosyası olarak çalıştırırsanız.
Quintec

1
etkileşimli kabuk üzerinden kod koyma davranışıdır. İşlev kullanılmadan değer döndürürse, yorumlayıcı bunu hata ayıklama çıktısı olarak kabuğa yazdırır
Reishin

2

Hala anlamayanlar için.

>>> 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

Diğerlerinin söylediği gibi, nextyineleyiciyi beklendiği gibi 1 arttırır. Döndürülen değerini bir değişkene atamak, davranışını sihirli bir şekilde değiştirmez.


1

Bir işlev olarak çağrıldığında istediğiniz şekilde davranır:

>>> def test():
...     a = iter(list(range(10)))
...     for i in a:
...         print(i)
...         next(a)
... 
>>> test()
0
2
4
6
8
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.