web-dev-qa-db-fra.com

Python liste le comportement de l'itérateur et le suivant (itérateur)

Considérer:

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

Ainsi, la progression de l'itérateur est, comme prévu, gérée par la mutation de ce même objet.

Ceci étant, je m'attendrais à:

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

pour ignorer chaque deuxième élément: l'appel à next doit faire avancer l'itérateur une fois, puis l'appel implicite effectué par la boucle doit le faire avancer une seconde fois - et le résultat de ce deuxième appel sera attribué à i.

Ce n'est pas. La boucle imprime tous des éléments de la liste, sans en ignorer.

Ma première pensée a été que cela pourrait se produire car la boucle appelle iter sur ce qu'elle est passée, et cela peut donner un itérateur indépendant - ce n'est pas le cas, car nous avons iter(a) is a.

Alors, pourquoi next ne semble-t-il pas faire avancer l'itérateur dans ce cas?

131
lvc

Ce que vous voyez est le interprète reprenant la valeur de retour de next() en plus de i en cours d'impression à chaque itération:

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

Donc, 0 est la sortie de print(i), 1 la valeur renvoyée par next(), répercutée par l'interpréteur interactif, etc. Il n'y a que 5 itérations, chaque itération aboutissant à 2 lignes en cours d'écriture sur le terminal.

Si vous affectez la sortie de next(), les choses fonctionnent comme prévu:

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

ou print extra informations permettant de différencier la sortie print() de l'interpréteur interactif echo:

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

En d'autres termes, next() fonctionne comme prévu, mais comme il renvoie la valeur suivante de l'itérateur, répercuté par l'interpréteur interactif, vous êtes amené à croire que la boucle a sa propre copie d'itérateur.

182
Martijn Pieters

Ce qui se passe, c'est que next(a) renvoie la valeur suivante de a, qui est imprimée sur la console car elle n'est pas affectée.

Ce que vous pouvez faire, c'est affecter une variable avec cette valeur:

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

Je trouve les réponses existantes un peu déroutantes, car elles ne font qu'indiquer indirectement l'essentiel de la mystification dans l'exemple de code: les deux * le "print i" et le "next (a)" entraîne l'impression de leurs résultats.

Comme ils impriment des éléments alternés de la séquence d'origine et qu'il est inattendu que l'instruction "next (a)" soit en cours d'impression, il semble que l'instruction "print i" imprime toutes les valeurs.

Dans cette optique, il devient plus clair qu'attribuer le résultat de "next (a)" à une variable empêche l'impression de son résultat, de sorte que seules les valeurs alternatives que la variable de boucle "i" sont imprimées. De même, faire en sorte que la déclaration "print" émette quelque chose de plus distinctif la désambiguise également.

(Une des réponses existantes réfute les autres car cette réponse consiste à faire évaluer l'exemple de code en tant que bloc, de sorte que l'interpréteur ne signale pas les valeurs intermédiaires de "next (a)".)

Ce qui est séduisant en répondant aux questions, en général, est d’expliciter ce qui est évident une fois que vous connaissez la réponse. Cela peut être insaisissable. De même, critiquer les réponses une fois que vous les comprenez. C'est intéressant...

7
klm

Pour ceux qui ne comprennent toujours pas.

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

Comme d'autres l'ont déjà dit, next augmente l'itérateur de 1 comme prévu. L'affectation de la valeur renvoyée à une variable ne modifie pas son comportement comme par magie.

2
Wesley

Quelque chose ne va pas avec votre Python/ordinateur.

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

>>> 
0
2
4
6
8

Fonctionne comme prévu.

Testé en Python 2.7 et en Python 3+. Fonctionne correctement dans les deux

2
Inbar Rose

Il se comporte comme vous le souhaitez s'il est appelé en tant que fonction:

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