a = range(1, 3)
a = iter(a)
list(a)
a = list(a)
a
s'évalue à [ ]
.
a = range(1, 3)
a = iter(a)
a = list(a)
a
s'évalue à [1, 2]
.
Le premier résultat est inattendu pour moi. Quelle est la sémantique qui se joue ici ?
a = range(1, 3)
a = iter(a)
list(a)
a = list(a)
a
s'évalue à [ ]
.
a = range(1, 3)
a = iter(a)
a = list(a)
a
s'évalue à [1, 2]
.
Le premier résultat est inattendu pour moi. Quelle est la sémantique qui se joue ici ?
La question n'est pas list()
mais iter()
qui, comme indiqué, renvoie un iterator
. Une fois que quelque chose a accédé au iterator
l'itérateur est définitivement vide. L'outil le plus couramment utilisé, le itérable est (normalement) réutilisable, et les deux types ne doivent pas être confondus.
Notez que vous n'avez pas besoin de iter()
pour transformer un range
en un list
parce que list()
prend un iterable
comme argument :
>>> a = range(1, 3)
>>> list(a)
[1, 2]
>>> list(a)
[1, 2]
Et ce n'est que le iterator
renvoyée par iter()
qui est à usage unique :
>>> b = iter(a)
>>> list(b)
[1, 2]
>>> list(b)
[]
>>> list(a)
[1, 2]
Voyons ce qui se passe :
>>> a = range(1, 3)
>>> a is iter(a)
False
comme vous pouvez le constater, iter
donne un nouvel objet itérateur, qui n'est pas a
sí mismo
>>>> a = iter(a)
le nom a
correspond désormais à l'objet itérateur distinct iter
nous a donné (comme si iter(a)
s'était retourné lui-même, comme c'est le cas avec zip
et avec des fichiers)
>>> list(a)
[1, 2]
épuise l'itérateur, donc
>>> list(a)
[]
ne donne rien car l'itérateur a déjà été utilisé (itéré)
Voici quelques expériences supplémentaires que vous pouvez tenter pour bien comprendre ce qui se passe :
>>> a = range(1, 3)
>>> a
range(1, 3)
>>> type(a)
<class 'range'>
>>> b = iter(a)
>>> b
<range_iterator object at 0x7f331a6d96c0>
>>> type(b)
<class 'range_iterator'>
>>> a is b
False
>>> list(b)
[1, 2]
>>> list(b)
[]
>>> list(a)
[1, 2]
>>> list(a)
[1, 2]
>>> a
range(1, 3)
>>> next(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'range' object is not an iterator
>>> b=iter(a)
>>> next(b)
1
>>> next(b)
2
>>> next(b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> a=[1,2,3]
>>> b=[4,5,6]
>>> z=zip(a,b)
>>> iter(z) is z
True
>>> with open('words.txt') as f:
... iter(f) is f
...
True
Remarque : sous Python 2, plusieurs fonctions renvoient des listes au lieu d'itérateurs (par ex. zip
)
a = iter(a)
list(a)
^^^^^^^
Signifie convertir un itérateur en une liste, et ne pas enregistrer la sortie. Cependant, un itérateur ne peut produire que la sortie une fois . Après avoir lisez-le il deviendra vide.
Et si vous essayez next()
ici, vous pouvez également voir ce qui se passe :
>>> next(a)
1
>>> next(a)
2
>>> next(a)
Traceback (most recent call last):
File "<input>", line 1, in <module>
StopIteration
>>> list(a)
[]
En le document :
Objet représentant un flux de données. Les appels répétés à la fonction
__next__()
(ou en la passant à la fonction intégréenext()
) renvoient des éléments successifs dans le flux.Lorsqu'il n'y a plus de données disponibles, une exception StopIteration est levée. À ce stade, l'objet itérateur est épuisé et tout appel ultérieur à l'objet
__next__()
se contente de relancer StopIteration.
Créer une liste à partir d'un itérateur consomme l'itérateur. En d'autres termes, ses éléments sont créés lorsque cela est nécessaire et le contenu de l'itérateur est vide après l'itération. Si vous souhaitez une autre copie d'un itérateur, par exemple pour créer une liste, vous pouvez utiliser itertools.tee
.
>>> from itertools import tee
>>> it1, it2 = tee(range(1,3))
>>> lst = list(it1)
>>> lst
[1, 2]
>>> for x in it2:
... print(x)
...
1
2
>>> list(it2) # it2 is now exhausted
[]
list(thing)
signifie itérer tous les éléments de thing
(en tant que for item in thing
) et enregistrer tous les éléments dans une nouvelle liste.
iter(thing)
signifie obtenir un "itérateur" pour thing
; un itérateur est en fait un marqueur dans un flux de données qui se souvient de l'endroit où l'on se trouve et qui peut être utilisé pour obtenir l'élément suivant du flux (en faisant avancer le "marqueur" en tant qu'effet secondaire). Il est explicitement n'est pas n'a aucun moyen de réinitialiser le marqueur au début pour répéter l'itération ; ceci afin de pouvoir prendre en charge l'itération de choses qui, par nature, ne peuvent pas être itérées plusieurs fois.
Itération de tous les éléments de thing
(en tant que for item in thing
) obtient un itérateur pour thing
et utilise ensuite l'itérateur pour récupérer tous les éléments de la chose. Donc, si vous faites ceci :
a = range(1, 3)
for x in a:
print x
for x in a:
print x
La boucle for crée un nouvel itérateur pour a
(qui commence avec le marqueur au début de la plage), puis tire des éléments de l'itérateur jusqu'à la fin de la plage. L'objet plage lui-même n'est pas touché, de sorte que la deuxième boucle for peut créer un nouvel itérateur (en commençant à nouveau au début) et l'itérer à nouveau.
Mais ici :
a = range(1, 3)
a = iter(a)
for x in a:
print x
for x in a:
print x
Vous ne laissez pas la boucle for créer un itérateur pour la plage, mais vous le faites explicitement, et une seule fois. Lorsque la boucle for va créer un itérateur à partir de a
l'itérateur qu'il obtient est juste a
elle-même ( iter(i)
quand i
est un itérateur doit toujours renvoyer i
). La boucle "for" extrait donc les éléments de a
en avançant le marqueur à chaque fois, jusqu'à ce que le marqueur soit "hors de l'extrémité" de l'objet de la gamme.
Ensuite, la deuxième boucle for crée un itérateur à partir de l'itérateur a
et obtient à nouveau a
même. Il tire ensuite des éléments de cet itérateur jusqu'à ce qu'il soit épuisé, ce qu'il peut faire zéro fois parce que a
est déjà "en dehors de la fin".
Cela n'a donc rien à voir avec votre list
directement, c'est juste la façon dont les objets itérateurs que vous obtenez avec iter
se comporter. D'ordinaire, on n'utilise pas iter
car les éléments que vous utilisez pour itérer des collections (boucles for, list()
, etc) déjà gèrent la création d'itérateurs pour vous. Vous n'utiliserez que iter
lorsque vous faites quelque chose de compliqué impliquant partiellement en consommant un itérateur, puis en consommant d'autres éléments à partir de l'endroit où la première itération partielle s'est arrêtée.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.