Les Python Iterators sont des objets Python com­por­tant un ensemble quan­ti­fiable d’éléments per­met­tant d’im­plé­men­ter le protocole de l’itérateur composé des deux fonctions iter() et next().

Python Iterators : de quoi s’agit-il exac­te­ment ?

Les Python Iterators sont d’abord une forme spéciale d’objets Python. Ils se dis­tin­guent par leur com­po­si­tion : ils sont en effet cons­ti­tués d’un ensemble quan­ti­fiable d’éléments. Il est donc possible de compter les éléments d’un itérateur et d’itérer sur tous les éléments d’un Python Iterator.

Conseil

Python est un excellent langage de pro­gram­ma­tion, tout par­ti­cu­liè­re­ment adapté au dé­ve­lop­pe­ment de projets Web. Faites appel à l’outil Deploy Now pour votre projet Web et profitez de l’en­vi­ron­ne­ment de création et de dé­ploie­ment au­to­ma­tiques de GitHub, pour bé­né­fi­cier d’une vue d’ensemble sur votre projet à tout moment.

Iterators ou Iterables ?

Il convient de ne pas confondre un Python Iterator avec un Python Iterable, même si ces deux éléments sont étroi­te­ment liés. Les dif­fé­rents itérables, comme la liste Python, se dis­tin­guent par l’uti­li­sa­tion d’une méthode iter(), par l’in­ter­mé­diaire de laquelle ils peuvent itérer. Pour ne pas les confondre, vous pouvez raisonner ainsi : tous les éléments po­si­tion­nés à droite de l’en-tête de boucle au moment de l’appel d’une boucle for sont des itérables.

l = [1, 2, 3]
for x in l:
	print(x)
Python

Comme vous pouvez le voir, la liste en­re­gis­trée dans la variable « l » apparaît à droite de l’en-tête de la boucle, après le mot-clé « in », lors de l’appel de la boucle for en Python ; il s’agit donc d’un itérable.

Il est possible de dériver un Python Iterator d’un Python Iterable. Vous trouverez ci-dessous un exemple de code pour clarifier cet état de fait et mieux com­prendre les dif­fé­rences entre les deux éléments :

string = "test"
iteratorobject = iter(string)
next(iteratorobject)
iter(iteratorobject)
Python

Dans le code, une chaîne de ca­rac­tères Pythoncom­por­tant la valeur test est en­re­gis­trée dans la variable appelée « string ». Les chaînes de ca­rac­tères relèvent elles aussi de la catégorie des Iterables, car une itération peut s’effectuer par l’in­ter­mé­diaire de chaque lettre de la chaîne de ca­rac­tères.

Le fait que les chaînes de ca­rac­tères per­met­tent des ité­ra­tions sous-entend en réalité que ces chaînes prennent également en charge la fonction iter(). Cet état de fait est illustré dans la ligne de code suivante, où nous créons un Python Iterator en appelant la fonction iter() en même temps que la chaîne de ca­rac­tères pré­cé­dem­ment créée. Celle-ci renvoie un pointeur vers la chaîne de ca­rac­tères, qu’elle en­re­gistre dans la variable appelée « ite­ra­to­rob­ject ». Le Python Iterator se trouve donc dans un état donné. Cet état peut être modifié par l’appel de la méthode next() sur le Python Iterator. La méthode permet de déplacer le pointeur d’un caractère, de manière que la valeur ite­ra­to­rob­ject cible la première lettre de la chaîne de ca­rac­tères après l’appel de fonction.

L’appel de la fonction iter(), qui utilise le Python Iterator en tant que paramètre de transfert, renvoie une référence à celui-ci. Les Python Iterators sont donc auto-itérables.

Iterators ou Ge­ne­ra­tors ?

Il est également essentiel d’établir une dis­tinc­tion entre les Python Iterators et les Python Ge­ne­ra­tors. Si chaque Python Generator est un Python Iterator, l’inverse n’est pas forcément vrai. En effet, con­trai­re­ment à un Python Generator, un Python Iterator n’est pas né­ces­sai­re­ment créé avec une fonction com­por­tant une ex­pres­sion yield.

Conseil

Les Python Iterators relèvent d’une technique de pro­gram­ma­tion avancée, qui n’est pas ex­pli­ci­tée dans tous les tutoriels Python. Si vous souhaitez découvrir d’autres tech­niques avancées en lien avec Python, nous vous con­seil­lons de vous in­té­res­ser aux articles suivants :

Uti­li­sa­tion des Python Iterators : pourquoi et dans quel but ?

Bien entendu, les Python Iterators sont avant tout utilisés à des fins d’itération. Le principal avantage des Python Iterators réside dans leur fonc­tion­ne­ment, basé sur le principe d’une «lazy eva­lua­tion» (lit­té­ra­le­ment « éva­lua­tion pa­res­seuse »). En d’autres termes, chaque élément d’un Python Iterator peut être traité de façon in­di­vi­duelle sans qu’il soit né­ces­saire de charger in­té­gra­le­ment la structure de données en mémoire. Cette solution comporte des avantages en matière d’ef­fi­ca­cité, surtout si vous devez traiter d’im­por­tants volumes de données où un seul élément doit être chargé à la fois.

Python Iterators : comment les créer ?

Vous pouvez fa­ci­le­ment créer votre propre Python Iterator. Pour ce faire, ajoutez sim­ple­ment les fonctions iter() et next() à un objet Python ; cela vous permet de créer fa­ci­le­ment un Python Iterator qui renvoie tous les nombres pairs. L’exemple ci-dessous illustre la marche à suivre :

class nombrespairs:
	def __iter__(self):
		self.x = 0
		return self
	def __next__(self):
		a = self.x
		self.x += 2
		return a
testobject = nombrespairs()
testiterator = iter(testobject)
print(next(testiterator))
print(next(testiterator))
print(next(testiterator))
print(next(testiterator))
Python

Pour créer un Python Iterator, vous devez commencer par créer une classe. Ici, elle est appelée « nom­bres­pairs ». Au sein de cette classe, il convient ensuite d’im­plé­men­ter les deux fonctions iter() et next(), chacune adoptant le com­por­te­ment souhaité.

Dans notre cas, la fonction iter() se contente de renvoyer une référence au Python Iterator devant héberger la suite de nombres entiers (en com­men­çant par 0). La logique de l’itération, c’est-à-dire le fait de ne renvoyer qu’un nombre sur deux (et donc un nombre pair) est prise en charge par la fonction next().

Une fois la classe définie, un objet de celle-ci est créé et en­re­gis­tré au sein de la variable portant le nom « tes­tob­ject ». Cet objet devient un Python Iterator dès lors que la fonction iter() est appelée, comme nous l’avons vu dans l’exemple de code précédent. Quatre appels de la fonction next() sont ensuite effectués, et leurs résultats s’affichent à l’écran. Le résultat de la section de code ci-dessus se présente de la manière suivante :

0
2
4
6

Python Iterators : comment les limiter ?

Le Python Iterator res­pon­sable de l’itération sur les nombres pairs pourrait s’exécuter à l’infini, les nombres pairs n’ayant tech­ni­que­ment pas de fin ; il convient donc de le limiter. Pour ce faire, vous pouvez combiner une dé­cla­ra­tion Sto­pI­te­ra­tion et une dé­cla­ra­tion if…else en Python. Imaginons par exemple que vous sou­hai­tiez afficher dans votre Python Iterator tous les nombres pairs jusqu’à 100 (inclus). L’exemple de code ci-dessous vous aiguille sur la marche à suivre :

class nombrespairs:
	def __iter__(self):
		self.x = 0
		return self
	def __next__(self):
		if self.x <= 100:
			a = self.x
			self.x += 2
			return a	
		else:
			StopIteration
testobject = nombrespairs()
testiterator = iter(testobject)
print(next(testiterator))
print(next(testiterator))
print(next(testiterator))
print(next(testiterator))
Python

Dans le code, rien n’a changé, si ce n’est la fonction d’im­plé­men­ta­tion next(). Ici, une dé­cla­ra­tion if…else sup­plé­men­taire a été ajoutée. Elle s’assure que chaque nombre traité est bien inférieur ou égal à 100 et l’itération dans l’ensemble des nombres pairs ne peut se pour­suivre qu’à cette condition. Dès que le nombre traité dépasse 100, l’appel de la dé­cla­ra­tion Sto­pI­te­ra­tion renvoie une erreur.

Aller au menu principal