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.