Les réponses ci-dessus sont excellentes, mais comme la plupart de ce que j'ai vu, n'insistez pas sur la distinction assez sur pour les gens comme moi.
De plus, les gens ont tendance à devenir "trop Pythonique" en mettant des définitions comme "X est un objet qui a __foo__()
méthode" auparavant. De telles définitions sont correctes - elles sont basées sur la philosophie du typage du canard, mais l'accent mis sur les méthodes tend à se mettre entre les deux lorsque l'on essaie de comprendre le concept dans sa simplicité.
J'ajoute donc 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,
itérable est un objet qui est, bien, itérable, ce qui signifie simplement qu'il peut être utilisé en itération, par exemple avec une for
boucle. Comment? En utilisant l' itérateur . J'expliquerai ci-dessous.
... tandis que l' itérateur est un objet qui définit comment faire réellement l'itération - en particulier quel est l' élément suivant . C'est pourquoi il doit avoir une
next()
méthode.
Les itérateurs sont eux-mêmes également itérables, à la différence près que leur __iter__()
méthode renvoie le même objet ( self
), que ses éléments aient ou non été consommés par des appels précédents à next()
.
Alors, que pense l'interprète Python quand il voit une for x in obj:
déclaration?
Regardez, une for
boucle. On dirait un travail pour un itérateur ... Prenons-en un. ... Il y a ce obj
gars, alors demandons-lui.
"M. obj
, avez-vous votre itérateur?" (... appels iter(obj)
, qui appelle
obj.__iter__()
, qui distribue avec bonheur un nouvel itérateur brillant _i
.)
OK, c'était facile ... Commençons alors à répéter. ( x = _i.next()
... x = _i.next()
...)
Puisque M. a obj
réussi ce test (en ayant une certaine méthode renvoyant un itérateur valide), nous le récompensons avec un adjectif: vous pouvez maintenant l'appeler "M. itérable obj
".
Cependant, dans des cas simples, vous ne bénéficiez pas normalement d'avoir un itérateur et un itérable séparément. Vous définissez donc un seul objet, qui est également son propre itérateur. (Python ne se soucie pas vraiment de ce que _i
distribué par obj
n'était pas si brillant, mais juste obj
lui - même.)
C'est pourquoi dans la plupart des exemples que j'ai vus (et ce qui m'avait confus 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 y a des cas, cependant, où vous pouvez bénéficier d'avoir l'itérateur séparé de l'itérable, comme quand vous voulez avoir une ligne d'éléments, mais plus de "curseurs". Par exemple, lorsque vous souhaitez travailler avec des éléments "actuels" et "à venir", vous pouvez avoir des itérateurs séparés pour les deux. Ou plusieurs threads tirés d'une énorme liste: chacun peut avoir son propre itérateur pour parcourir tous les éléments. Voir @ Raymond's et @ glglgl's réponses de 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 le répète: l' itérateur n'est pas itérable . L'itérateur ne peut pas être utilisé comme "source" en for
boucle. Ce dont la for
boucle a principalement besoin est __iter__()
(qui renvoie quelque chose avec next()
).
Bien sûr, ce for
n'est pas la seule boucle d'itération, donc ci-dessus s'applique également à d'autres constructions ( while
...).
Les itérateurs next()
peuvent lancer StopIteration pour arrêter l'itération. Cela ne doit pas, cependant, il peut répéter 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 Python 3.x: la next()
méthode (pas la fonction intégrée) doit maintenant être appelée __next__()
. Oui, ça aurait dû être comme ça tout le temps.
Vous pouvez également penser à cela comme ceci: l'itérable a les données, l'itérateur tire l'élément suivant
Avertissement: je ne suis pas un développeur d'interpréteur Python, donc je ne sais pas vraiment ce que "l'interprète" pense. Les réflexions ci-dessus sont uniquement une démonstration de la façon dont je comprends le sujet à partir d'autres explications, expériences et expériences réelles d'un débutant en Python.
collections.abc.AsyncIterator
tests__aiter__
et les__anext__
méthodes. Il s'agit d'un nouvel ajout en 3.6.