web-dev-qa-db-fra.com

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

Quelle est la définition la plus élémentaire de "iterable", "iterator" et "iteration" en Python?

J'ai lu plusieurs définitions mais je ne parviens pas à identifier le sens exact car il ne sera toujours pas intégré.

Quelqu'un peut-il m'aider s'il vous plaît avec les 3 définitions en termes simples?

395
thechrishaddad

Itération est un terme général désignant chaque élément de quelque chose, l'un après l'autre. Chaque fois que vous utilisez une boucle, explicite ou implicite, pour parcourir un groupe d’éléments, c’est une itération.

En Python, iterable et iterator ont une signification spécifique.

Un iterable est un objet qui a une méthode __iter__ qui retourne un iterator , ou qui définit un __getitem__ méthode qui peut prendre des index séquentiels à partir de zéro (et déclenche un IndexError lorsque les index ne sont plus valides). Donc un iterable est un objet dont vous pouvez obtenir un iterator .

Un iterator est un objet avec une méthode next (Python 2) ou __next__ (Python 3).

Chaque fois que vous utilisez une boucle for, ou map, ou une compréhension de liste, etc. en Python, la méthode next est automatiquement appelée pour obtenir chaque élément de itérateur , passant ainsi par le processus de itération .

Un bon endroit pour commencer à apprendre serait le section des itérateurs du tutoriel et le section des types d'itérateurs de la page des types standard . Une fois que vous avez compris les bases, essayez la section itérateurs du HOWTO Programmation fonctionnelle .

470
agf

Voici l'explication que j'utilise dans l'enseignement de Python classes:

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 à droite 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 retourne un ITERATOR neuf, ou une méthode __getitem__ appropriée pour la recherche indexée.

Un ITERATOR est un objet:

  • avec l'état qui se souvient où il est pendant l'itération,
  • avec une méthode __next__ qui:
    • renvoie la valeur suivante dans l'itération
    • met à jour l'état pour pointer vers la valeur suivante
    • signaux quand il est fait en soulevant StopIteration
  • et c’est auto-itérable (c’est-à-dire qu’il a une méthode __iter__ qui retourne self).

Remarques:

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

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
302
Raymond Hettinger

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

De plus, les gens ont tendance à se faire "trop ​​Pythonic" en mettant des définitions comme "X est un objet qui a la méthode __foo__() avant". Ces définitions sont correctes - elles sont basées sur la philosophie de la typographie, mais l'accent mis sur les méthodes a tendance à se situer entre les efforts lorsque l'on tente de comprendre le concept dans sa simplicité.

Alors j'ajoute ma version.


En langage naturel,

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

En python,

  • iterable est un objet qui est, ainsi, iterable, ce qui signifie simplement qu'il peut être utilisé dans une itération, par exemple. avec une boucle for. Comment? En utilisant itérateur . Je vais expliquer ci-dessous.

  • ... while itérateur est un objet qui définit comment effectuer l'itération - spécifiquement quel est le prochain élément. C'est pourquoi il doit avoir la méthode next().

Les itérateurs sont eux aussi itératifs, à la différence que leur méthode __iter__() renvoie le même objet (self), que ses éléments aient été consommés ou non lors d'appels précédents à next().


Alors, que pense l’interprète Python quand il voit la déclaration for x in obj:?

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

"M. obj, avez-vous votre itérateur?" (... appelle iter(obj), qui appelle obj.__iter__(), qui distribue avec bonheur un nouvel itérateur brillant _i.)

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

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

Cependant, dans les cas simples, il n'est normalement pas avantageux d'avoir itérateur et itérable séparément. Vous définissez donc un seul objet , qui est également son propre itérateur. (Python ne s'inquiète pas vraiment que _i distribué par obj n'était pas si brillant, mais juste le obj lui-même.)

C'est pourquoi, dans la plupart des exemples que j'ai vus (et ce qui m'avait dérouté encore et encore), vous pouvez 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()

Il existe cependant des cas dans lesquels vous pouvez tirer avantage de la séparation de l'itérateur de l'itérable, par exemple lorsque vous souhaitez avoir une ligne d'éléments, mais davantage de "curseurs". Par exemple, lorsque vous souhaitez utiliser les éléments "en cours" et "à venir", vous pouvez avoir des itérateurs séparés pour les deux. Ou plusieurs threads tirés d'une liste énorme: chacun peut avoir son propre itérateur à parcourir sur tous les éléments. Voir les réponses @ Raymond's et @ glglgl's 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()

Remarques:

  • Je répète: l'itérateur n'est pas itérable . L'itérateur ne peut pas être utilisé comme "source" dans la boucle for. La boucle for dont nous avons principalement besoin est __iter__() (qui renvoie quelque chose avec next()).

  • Bien entendu, for n’est pas la seule boucle d’itération, ce qui précède s’applique également à certaines autres constructions (while...).

  • La fonction next() d'Iterator peut lancer StopIteration pour arrêter l'itération. N'a pas à le faire, cependant, il peut itérer pour toujours 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 la méthode Python 3.x: _ La méthode next() (et non la fonction intégrée) doit maintenant s'appeler __next__(). Oui, ça aurait dû être comme ça depuis le début.

  • Vous pouvez aussi penser à ça comme ceci: iterable a les données, iterator tire le prochain article

Avertissement: Je ne suis développeur d'aucun interpréteur Python, je ne sais donc pas vraiment ce que l'interprète "pense". Les réflexions ci-dessus démontrent uniquement comment je comprends le sujet à partir d'autres explications, expériences et expériences réelles d'un débutant Python.

94
Alois Mahdal

Un iterable est un objet qui a une méthode __iter__(). Il peut éventuellement être itéré plusieurs fois, tels que list()s et Tuple()s.

Un itérateur est l'objet qui itère. Elle est renvoyée par une méthode __iter__(), se renvoie elle-même via sa propre méthode __iter__() et possède une méthode next() (__next__() dans 3.x).

L'itération est le processus d'appel de cette next() resp. __next__() jusqu'à ce qu'il augmente 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
21
glglgl

Je ne sais pas si cela aide quelqu'un, mais j'aime toujours visualiser des concepts dans ma tête pour mieux les comprendre. Donc, comme j'ai un petit fils, je visualise un concept itérable/itérateur avec des briques et du papier blanc.

Supposons que nous sommes dans la pièce sombre et sur le sol que nous avons des briques pour mon fils. Des briques de différentes tailles, couleurs, n’a plus d’importance. Supposons que nous ayons 5 briques comme celles-ci. Ces 5 briques peuvent être décrites comme un objet - disons kit de briques . Nous pouvons faire beaucoup de choses avec ce kit de briques - nous pouvons en prendre une, puis prendre la deuxième et la troisième, puis changer de place de briques, placer la première brique au-dessus de la seconde. Nous pouvons faire beaucoup de choses avec cela. Par conséquent, ce kit de briques est un objet itérable ou séquence car nous pouvons passer en revue chaque brique et en faire quelque chose. Nous ne pouvons le faire que comme mon petit fils - nous pouvons jouer avec ne brique à la fois. Alors encore une fois, je m'imagine que ce kit de briques est un iterable.

Maintenant rappelez-vous que nous sommes dans la pièce sombre. Ou presque sombre. Le fait est que nous ne voyons pas clairement ces briques, leur couleur, leur forme, etc. Donc, même si nous voulons faire quelque chose avec elles - aka parcourir par elles - nous ne le faisons pas vraiment savoir quoi et comment car il fait trop sombre.

Ce que nous pouvons faire, c'est près de la première brique - en tant qu'élément d'un kit de briques - nous pouvons mettre un morceau de papier fluorescent blanc afin de nous permettre de voir où se trouve le premier élément de brique. Et chaque fois que nous prenons une brique d'un kit, nous remplaçons le morceau de papier blanc par une brique suivante afin de pouvoir le voir dans la pièce sombre. Ce morceau de papier blanc n’est rien de plus qu’un itérateur. C'est un objet aussi. Mais un objet avec lequel nous pouvons travailler et jouer avec des éléments de notre kit éditable d’objets - briques.

Cela explique d'ailleurs ma première erreur lorsque j'ai essayé ce qui suit dans un IDLE et obtenu un TypeError:

 >>> X = [1,2,3,4,5]
 >>> next(X)
 Traceback (most recent call last):
    File "<pyshell#19>", line 1, in <module>
      next(X)
 TypeError: 'list' object is not an iterator

La liste X ici était notre kit de briques mais PAS un morceau de papier blanc. Je devais d'abord trouver un itérateur:

>>> X = [1,2,3,4,5]
>>> bricks_kit = [1,2,3,4,5]
>>> white_piece_of_paper = iter(bricks_kit)
>>> next(white_piece_of_paper)
1
>>> next(white_piece_of_paper)
2
>>>

Je ne sais pas si ça aide, mais ça m’a aidé. Si quelqu'un pouvait confirmer/corriger la visualisation du concept, je vous en serais reconnaissant. Cela m'aiderait à en apprendre plus.

9
Nikolay Dudaev

Voici mon aide-mémoire:

 sequence
  +
  |
  v
   def __getitem__(self, index: int):
  +    ...
  |    raise IndexError
  |
  |
  |              def __iter__(self):
  |             +     ...
  |             |     return <iterator>
  |             |
  |             |
  +--> or <-----+        def __next__(self):
       +        |       +    ...
       |        |       |    raise StopIteration
       v        |       |
    iterable    |       |
           +    |       |
           |    |       v
           |    +----> and +-------> iterator
           |                               ^
           v                               |
   iter(<iterable>) +----------------------+
                                           |
   def generator():                        |
  +    yield 1                             |
  |                 generator_expression +-+
  |                                        |
  +-> generator() +-> generator_iterator +-+

Quiz: Voyez-vous comment ...

  • chaque itérateur est un itérable?
  • la méthode __iter__() d'un objet conteneur peut être implémentée en tant que générateur?
  • une méthode itérative plus une méthode __next__ n'est pas nécessairement un itérateur?
7
AXO

Iterable: - quelque chose qui est iterable est iterable; comme des séquences telles que des listes, des chaînes, etc. De plus, il possède soit la méthode __getitem__, soit une méthode __iter__. Maintenant, si nous utilisons la fonction iter() sur cet objet, nous aurons un itérateur.

Itérateur: - Lorsque nous obtenons l'objet itérateur de la fonction iter(); nous appelons la méthode __next__() (en python3) ou simplement next() (en python2) pour obtenir les éléments un à un. Cette classe ou instance de cette classe s'appelle un itérateur.

De la documentation: -

L'utilisation d'itérateurs imprègne et unifie Python. En coulisse, l'instruction for appelle iter() sur l'objet conteneur. La fonction renvoie un objet itérateur définissant la méthode __next__(), qui accède aux éléments du conteneur, un à la fois. Lorsqu'il n'y a plus d'éléments, __next__() génère une exception StopIteration qui indique à la boucle for de se terminer. Vous pouvez appeler la méthode __next__() à l'aide de la fonction intégrée next(); Cet exemple montre comment tout cela fonctionne:

>>> s = 'abc'
>>> it = iter(s)
>>> it
<iterator object at 0x00A1DB50>
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
    next(it)
StopIteration

Ex d'un cours: -

class Reverse:
    """Iterator for looping over a sequence backwards."""
    def __init__(self, data):
        self.data = data
        self.index = len(data)
    def __iter__(self):
        return self
    def __next__(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]


>>> rev = Reverse('spam')
>>> iter(rev)
<__main__.Reverse object at 0x00A1DB50>
>>> for char in rev:
...     print(char)
...
m
a
p
s
4
Vicrobot

Je ne pense pas que vous puissiez l’obtenir beaucoup plus simplement que documentation , mais je vais essayer:

  • Iterable est quelque chose qui peut être itéré . En pratique, signifie généralement une séquence par ex. quelque chose qui a un début et une fin et un moyen de parcourir tous les éléments qu'il contient.
  • Vous pouvez penser Iterator en tant que pseudo-méthode d'assistance (ou pseudo-attribut) qui donne (ou maintient) l'élément suivant (ou le premier) dans l'élément iterable . (En pratique, c'est juste un objet qui définit la méthode next())

  • L'itération est probablement mieux expliquée par le Merriam-Webster définition du mot :

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

3
Kimvais
iterable = [1, 2] 

iterator = iter(iterable)

print(iterator.__next__())   

print(iterator.__next__())   

alors,

  1. iterable est un objet pouvant être survolé. par exemple. liste, chaîne, tuple, etc.

  2. utiliser la fonction iter sur notre objet iterable renverra un objet itérateur.

  3. maintenant cet objet itérateur a une méthode nommée __next__ (dans Python 3, ou tout simplement next dans Python 2) par laquelle peut accéder à chaque élément de iterable.

alors, SORTIE DE CODE CI-DESSUS SERA:

1

2

3
arpan kumar

Iterables possède une méthode __iter__ qui instancie un nouvel itérateur à chaque fois.

Itérateurs implémente une méthode __next__ qui renvoie des éléments individuels et une méthode __iter__ qui renvoie self.

Par conséquent, les itérateurs sont également itérables, mais les itérables ne sont pas des itérateurs.

Luciano Ramalho, Python Courant.

1
techkuz

Avant de traiter avec les itérables et les itérateurs, le facteur principal qui détermine l’itérateur et les itérateurs est la séquence.

Séquence: La séquence est la collecte de données

Iterable: Iterable est l'objet de type séquence qui prend en charge la méthode Iter.

Méthode Iter: la méthode Iter prend une séquence en tant qu'entrée et crée un objet appelé itérateur

Itérateur: Les itérateurs sont les objets qui appellent la méthode suivante et transversalement à travers la séquence. Lors de l'appel de la méthode suivante, l'objet retourné est renvoyé.

exemple:

x=[1,2,3,4]

x est une séquence qui consiste en une collecte de données

y=iter(x)

En appelant iter (x), il retourne un itérateur uniquement lorsque l'objet x a une méthode iter, sinon une exception est déclenchée. S'il renvoie itérateur, y est assigné comme ceci:

y=[1,2,3,4]

Comme y est un itérateur, il prend en charge la méthode next ()

Lors de l'appel de la méthode suivante, les éléments individuels de la liste sont renvoyés un par un.

Après avoir renvoyé le dernier élément de la séquence, si nous appelons à nouveau la méthode suivante, une erreur StopIteration est renvoyée.

exemple:

>>> y.next()
1
>>> y.next()
2
>>> y.next()
3
>>> y.next()
4
>>> y.next()
StopIteration
1
Shadow