548 votes

Que sont exactement itérateur, itérable et itération ?

Quelle est la définition la plus élémentaire de "iterable", "itérateur" et "itération" en Python ?

J'ai lu de multiples définitions mais je ne parviens pas à identifier le sens exact car je n'arrive toujours pas à m'y retrouver.

Quelqu'un peut-il m'aider à trouver les 3 définitions en termes simples ?

630voto

agf Points 45052

Itération est un terme général pour prendre chaque élément de quelque chose, l'un après l'autre. Chaque fois que vous utilisez une boucle, explicite ou implicite, pour passer en revue un groupe d'éléments, il s'agit d'une itération.

En Python, itérable y itérateur ont des significations spécifiques.

Un site itérable est un objet qui a un __iter__ qui renvoie un itérateur ou qui définit un __getitem__ qui peut prendre des index séquentiels à partir de zéro (et qui soulève un IndexError lorsque les index ne sont plus valides). Ainsi, un itérable est un objet que vous pouvez obtenir un itérateur de.

Un site itérateur est un objet avec un next (Python 2) ou __next__ (Python 3).

Chaque fois que vous utilisez un for boucle, ou map ou une compréhension de liste, etc. En Python, la fonction next est appelée automatiquement pour récupérer chaque élément de l'ensemble de la liste. itérateur en passant ainsi par le processus de itération .

Un bon endroit pour commencer à apprendre serait le section itérateurs du tutoriel et le section des types d'itérateurs de la page des types standards . Après avoir compris les principes de base, essayez les section itérateurs du guide pratique de la programmation fonctionnelle (Functional Programming HOWTO) .

0 votes

Cela m'embrouille beaucoup que tout ce qui a une __getitem__ est considérée comme itérable, mais toute méthode existante de __len__ est complètement ignorée. Le principe du moindre étonnement échoue ici...

3 votes

Notez que collections.abc.AsyncIterator des tests pour __aiter__ y __anext__ méthodes. Il s'agit d'un nouvel ajout dans la version 3.6.

2 votes

@jlh pourquoi __len__ être nécessairement liée à l'itération ? Comment le fait de connaître la longueur d'un objet peut-il vous aider à l'itérer ?

402voto

Raymond Hettinger Points 50330

Voici l'explication que j'utilise dans mes cours de Python :

Un ITERABLE est :

  • tout ce qui peut être bouclé (c'est-à-dire que vous pouvez boucler sur une chaîne ou un fichier) ou
  • tout ce qui peut apparaître sur le côté droit d'une boucle for : for x in iterable: ... ou
  • tout ce que vous pouvez appeler avec iter() qui retournera un ITERATOR : iter(obj) ou
  • un objet qui définit __iter__ qui renvoie un nouvel ITERATOR, ou il peut avoir un __getitem__ méthode adaptée à la recherche indexée.

Un ITERATOR est un objet :

  • avec un état qui se souvient où il se trouve pendant l'itération,
  • avec un __next__ méthode qui :
    • renvoie la valeur suivante dans l'itération
    • met à jour l'état pour pointer sur la prochaine valeur
    • les signaux lorsqu'il est fait en levant StopIteration
  • et c'est auto-itérable (ce qui signifie qu'il a un __iter__ qui renvoie self ).

Notes :

  • El __next__ dans Python 3 s'écrit next dans Python 2, et
  • La fonction intégrée next() appelle cette méthode sur l'objet qui lui est passé.

Par exemple :

>>> s = 'cat'      # s is an ITERABLE
                   # s is a str object that is immutable
                   # s has no state
                   # s has a __getitem__() method 

>>> t = iter(s)    # t is an ITERATOR
                   # t has state (it starts by pointing at the "c"
                   # t has a next() method and an __iter__() method

>>> next(t)        # the next() function returns the next value and advances the state
'c'
>>> next(t)        # the next() function returns the next value and advances
'a'
>>> next(t)        # the next() function returns the next value and advances
't'
>>> next(t)        # next() raises StopIteration to signal that iteration is complete
Traceback (most recent call last):
...
StopIteration

>>> iter(t) is t   # the iterator is self-iterable

3 votes

Qu'entendez-vous par itérateur frais ?

21 votes

@lmiguelvargasf "Frais" comme dans "nouveau et non consommé" par opposition à "épuisé ou partiellement consommé". L'idée est qu'un nouvel itérateur commence au début, tandis qu'un itérateur partiellement utilisé reprend là où il s'est arrêté.

1 votes

Vos deuxième, troisième et quatrième puces indiquent clairement ce que vous voulez dire, en termes de constructions, de modules intégrés ou d'appels de méthode spécifiques à Python. Mais le premier point ("tout ce qui peut être bouclé") n'est pas aussi clair. En outre, le premier point semble se chevaucher avec le deuxième point, puisque ce dernier traite des questions suivantes for et le premier point concerne le "bouclage". Pourriez-vous répondre à ces questions ?

120voto

Alois Mahdal Points 1840

Les réponses ci-dessus sont excellentes, mais comme la plupart de ce que j'ai vu, elles n'insistent pas sur la distinction assez pour des gens comme moi.

De même, les gens ont tendance à être "trop pythoniques" en mettant des définitions du type "X est un objet qui a __foo__() méthode" auparavant. De telles définitions sont correctes - elles sont basées sur la philosophie du "duck-typing", mais l'accent mis sur les méthodes a tendance à s'immiscer lorsqu'on essaie de comprendre le concept dans sa simplicité.

J'ajoute donc ma version.


En langage naturel,

  • itération est le processus qui consiste à prendre un élément à la fois dans une rangée d'éléments.

En Python,

  • itérable est un objet qui est, eh bien, itérable, ce qui signifie simplement que qu'il peut être utilisé par itération, par exemple avec un objet de type for boucle. Comment ? En utilisant itérateur . Je vais l'expliquer ci-dessous.

  • ... alors que itérateur est un objet qui définit comment faire réellement le site itération--spécifiquement quel est le prochain élément. C'est pourquoi il doit avoir next() méthode.

Les itérateurs sont eux-mêmes également itérables, à la différence que leur __iter__() retourne le même objet ( self ), indépendamment du fait que ses éléments aient été consommés ou non par des appels précédents à next() .


Alors, que pense l'interpréteur Python lorsqu'il voit for x in obj: déclaration ?

Regardez, un for loop. On dirait un travail pour un itérateur... Allons en chercher un. ... Il y a ce obj le gars, alors demandons-lui.

"Monsieur. obj , avez-vous votre itérateur ?" (... appels iter(obj) qui appelle obj.__iter__() qui distribue joyeusement un nouvel itérateur brillant _i .)

OK, c'était facile... Commençons à itérer alors. ( x = _i.next() ... x = _i.next() ...)

Depuis que M. obj a réussi ce test (en ayant une certaine méthode retournant un itérateur valide), nous le récompensons avec un adjectif : vous pouvez maintenant l'appeler "itérable M.". obj ".

Cependant, dans les cas simples, il n'est normalement pas utile d'avoir l'itérateur et l'itérable séparément. Vous définissez donc seulement un qui est aussi son propre itérateur. (Python ne se soucie pas vraiment que _i distribués par obj n'était pas si brillante, mais juste la obj lui-même.)

C'est pourquoi dans la plupart des exemples que j'ai vus (et ce qui m'avait dérouté à maintes reprises), on peut voir :

class IterableExample(object):

    def __iter__(self):
        return self

    def next(self):
        pass

au lieu de

class Iterator(object):
    def next(self):
        pass

class Iterable(object):
    def __iter__(self):
        return Iterator()

Dans certains cas, cependant, il peut être avantageux d'avoir un itérateur séparé de l'itérable, par exemple lorsque vous voulez avoir une rangée d'éléments, mais plusieurs "curseurs". Par exemple, lorsque vous voulez travailler avec des éléments "actuels" et "à venir", vous pouvez avoir des itérateurs séparés pour les deux. Ou plusieurs threads tirant d'une énorme liste : chacun peut avoir son propre itérateur pour parcourir tous les éléments. Voir @Raymond's y @glglgl's réponses ci-dessus.

Imaginez ce que vous pourriez faire :

class SmartIterableExample(object):

    def create_iterator(self):
        # An amazingly powerful yet simple way to create arbitrary
        # iterator, utilizing object state (or not, if you are fan
        # of functional), magic and nuclear waste--no kittens hurt.
        pass    # don't forget to add the next() method

    def __iter__(self):
        return self.create_iterator()

Notes :

  • Je vais le répéter encore une fois : l'itérateur n'est pas itérable . Iterator ne peut pas être utilisé comme une "source" dans for boucle. Qu'est-ce que for boucle a principalement besoin est __iter__() (qui renvoie quelque chose avec next() ).

  • Bien sûr, for n'est pas la seule boucle d'itération, donc ce qui précède s'applique à d'autres également ( while ...).

  • de l'itérateur next() peut lancer StopIteration pour arrêter l'itération. Il n'est pas obligé de le faire, mais il peut itérer indéfiniment ou utiliser d'autres moyens.

  • Dans le "processus de pensée" ci-dessus, _i n'existe pas vraiment. J'ai inventé ce nom.

  • Il y a un petit changement dans Python 3.x : next() (pas la méthode intégrée) maintenant doit être appelée __next__() . Oui, ça aurait dû être comme ça depuis le début.

  • Vous pouvez aussi le voir comme ceci : iterable a les données, iterator tire l'élément suivant. élément suivant

Avis de non-responsabilité : Je ne suis pas un développeur d'un interprète Python, donc je ne sais pas vraiment ce que l'interprète "pense". Les réflexions ci-dessus ne sont que la démonstration de la façon dont je comprends le sujet à partir d'autres explications, d'expériences et de l'expérience réelle d'un débutant en Python.

3 votes

C'est génial, mais je suis toujours un peu perdu. Je pensais que votre boîte jaune disait qu'un for a besoin d'un itérateur ("Regardez, une boucle for. Ça ressemble à un travail pour un itérateur... Trouvons-en un."). Mais vous dites ensuite dans les notes à la fin que "Iterator ne peut pas être utilisé comme source dans une for boucle"... ?

1 votes

Pourquoi mettez-vous juste pass dans le code pour ceux next définitions ? Je suppose que vous voulez simplement dire que quelqu'un doit implémenter un moyen d'obtenir le suivant, puisque le suivant doit retourner quelque chose.

1 votes

@nealmcb Oui, je pense que c'est ce que je voulais dire. (C'est ce que pass est pour après tout).

28voto

glglgl Points 35668

Un itérable est un objet qui possède un __iter__() méthode. Elle peut éventuellement être itérée plusieurs fois, comme par exemple list() et tuple() s.

Un itérateur est l'objet qui itère. Il est renvoyé par un __iter__() se retourne elle-même via sa propre méthode __iter__() et possède une next() méthode ( __next__() en 3.x).

L'itération est le processus qui consiste à appeler cette next() resp. __next__() jusqu'à ce qu'il soulève StopIteration .

Exemple :

>>> a = [1, 2, 3] # iterable
>>> b1 = iter(a) # iterator 1
>>> b2 = iter(a) # iterator 2, independent of b1
>>> next(b1)
1
>>> next(b1)
2
>>> next(b2) # start over, as it is the first call to b2
1
>>> next(b1)
3
>>> next(b1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> b1 = iter(a) # new one, start over
>>> next(b1)
1

1 votes

Donc, en réalité, c'est juste un objet qui passe à travers les conteneurs ? où cela serait-il utile ?

2 votes

Souvent, mais pas toujours. Un générateur, un fichier ou un curseur de base de données ne peuvent être itérés qu'une seule fois et sont donc leurs propres itérateurs.

1 votes

Je suppose que b2 n'a pas besoin d'être indépendant de b1 ? pour ce cas particulier, il est indépendant, bien sûr je peux le rendre non indépendant mais également valide. Iterable .

7voto

Kimvais Points 12453

Je ne pense pas que vous pouvez obtenir beaucoup plus simple que la documentation, mais je vais essayer:

  • Itérable est quelque chose qui peut être itéré . Dans la pratique, il habituellement signifie une séquence par exemple, quelque chose qui a un début et une fin et un moyen d'aller à travers tous les éléments qu'il contient.
  • Vous pouvez penser Itérateur comme une aide de pseudo-méthode (ou pseudo-attribut) qui donne (ou titulaire) le prochain (ou la première) à partir de la itérable. (Dans la pratique, il est juste un objet qui définit la méthode d' next())

  • L'itération s'explique sans doute par le Merriam-Webster définition du mot :

b : la répétition d'une séquence d'instructions de l'ordinateur spécifié nombre de fois ou jusqu'à ce qu'une condition est remplie - comparer la récursivité

Prograide.com

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.

Powered by:

X