Itérateurs Python
Itérateurs Python
Les itérateurs sont des objets sur lesquels on peut itérer. Dans ce didacticiel, vous apprendrez comment fonctionne l'itérateur et comment vous pouvez créer votre propre itérateur à l'aide des méthodes __iter__ et __next__.
Vidéo :Itérateurs Python
Itérateurs en Python
Les itérateurs sont partout en Python. Ils sont élégamment implémentés dans for
boucles, compréhensions, générateurs etc. mais sont cachés à la vue de tous.
Iterator en Python est simplement un objet sur lequel on peut itérer. Un objet qui renverra des données, un élément à la fois.
Techniquement parlant, un objet itérateur Python doit implémenter deux méthodes spéciales, __iter__()
et __next__()
, collectivement appelés le protocole itérateur .
Un objet est dit itérable si nous pouvons en obtenir un itérateur. La plupart des conteneurs intégrés à Python tels que :liste, tuple, chaîne, etc. sont itérables.
Le iter()
fonction (qui à son tour appelle la fonction __iter__()
méthode) renvoie un itérateur à partir d'eux.
Itérer à travers un itérateur
Nous utilisons le next()
fonction pour parcourir manuellement tous les éléments d'un itérateur. Lorsque nous arrivons à la fin et qu'il n'y a plus de données à renvoyer, cela lèvera le StopIteration
Exception. Voici un exemple.
# define a list
my_list = [4, 7, 0, 3]
# get an iterator using iter()
my_iter = iter(my_list)
# iterate through it using next()
# Output: 4
print(next(my_iter))
# Output: 7
print(next(my_iter))
# next(obj) is same as obj.__next__()
# Output: 0
print(my_iter.__next__())
# Output: 3
print(my_iter.__next__())
# This will raise error, no items left
next(my_iter)
Sortie
4 7 0 3 Traceback (most recent call last): File "<string>", line 24, in <module> next(my_iter) StopIteration
Une manière plus élégante d'itérer automatiquement consiste à utiliser la boucle for. En utilisant cela, nous pouvons parcourir n'importe quel objet pouvant renvoyer un itérateur, par exemple une liste, une chaîne, un fichier, etc.
>>> for element in my_list:
... print(element)
...
4
7
0
3
Fonctionnement de la boucle for pour les itérateurs
Comme nous le voyons dans l'exemple ci-dessus, le for
loop a pu parcourir automatiquement la liste.
En fait le for
loop peut itérer sur n'importe quel itérable. Examinons de plus près comment le for
boucle est en fait implémentée en Python.
for element in iterable:
# do something with element
Est en fait implémenté comme.
# create an iterator object from that iterable
iter_obj = iter(iterable)
# infinite loop
while True:
try:
# get the next item
element = next(iter_obj)
# do something with element
except StopIteration:
# if StopIteration is raised, break from loop
break
Donc en interne, le for
boucle crée un objet itérateur, iter_obj
en appelant le iter()
sur l'itérable.
Ironiquement, ce for
est en fait une boucle while infinie.
À l'intérieur de la boucle, il appelle next()
pour obtenir l'élément suivant et exécute le corps du for
boucle avec cette valeur. Une fois tous les éléments épuisés, StopIteration
est soulevé qui est pris à l'intérieur et la boucle se termine. Notez que tout autre type d'exception passera.
Construire des itérateurs personnalisés
Construire un itérateur à partir de zéro est facile en Python. Il suffit d'implémenter le __iter__()
et le __next__()
méthodes.
Le __iter__()
renvoie l'objet itérateur lui-même. Si nécessaire, une initialisation peut être effectuée.
Le __next__()
La méthode doit retourner l'élément suivant dans la séquence. En atteignant la fin, et dans les appels suivants, il doit lever StopIteration
.
Ici, nous montrons un exemple qui nous donnera la prochaine puissance de 2 à chaque itération. L'exposant de puissance commence à partir de zéro jusqu'à un nombre défini par l'utilisateur.
Si vous n'avez aucune idée de la programmation orientée objet, visitez la programmation orientée objet Python.
class PowTwo:
"""Class to implement an iterator
of powers of two"""
def __init__(self, max=0):
self.max = max
def __iter__(self):
self.n = 0
return self
def __next__(self):
if self.n <= self.max:
result = 2 ** self.n
self.n += 1
return result
else:
raise StopIteration
# create an object
numbers = PowTwo(3)
# create an iterable from the object
i = iter(numbers)
# Using next to get to the next iterator element
print(next(i))
print(next(i))
print(next(i))
print(next(i))
print(next(i))
Sortie
1 2 4 8 Traceback (most recent call last): File "/home/bsoyuj/Desktop/Untitled-1.py", line 32, in <module> print(next(i)) File "<string>", line 18, in __next__ raise StopIteration StopIteration
On peut aussi utiliser un for
boucle pour itérer sur notre classe d'itérateur.
>>> for i in PowTwo(5):
... print(i)
...
1
2
4
8
16
32
Itérateurs Python Infinis
Il n'est pas nécessaire que l'élément d'un objet itérateur soit épuisé. Il peut y avoir des itérateurs infinis (qui ne finissent jamais). Nous devons être prudents lors de la manipulation de tels itérateurs.
Voici un exemple simple pour démontrer les itérateurs infinis.
La fonction intégrée iter()
peut être appelé avec deux arguments où le premier argument doit être un objet appelable (fonction) et le second est la sentinelle. L'itérateur appelle cette fonction jusqu'à ce que la valeur renvoyée soit égale à la sentinelle.
>>> int()
0
>>> inf = iter(int,1)
>>> next(inf)
0
>>> next(inf)
0
Nous pouvons voir que le int()
fonction renvoie toujours 0. Donc, en le passant comme iter(int,1)
renverra un itérateur qui appelle int()
jusqu'à ce que la valeur renvoyée soit égale à 1. Cela n'arrive jamais et nous obtenons un itérateur infini.
Nous pouvons également construire nos propres itérateurs infinis. L'itérateur suivant retournera, théoriquement, tous les nombres impairs.
class InfIter:
"""Infinite iterator to return all
odd numbers"""
def __iter__(self):
self.num = 1
return self
def __next__(self):
num = self.num
self.num += 2
return num
Un exemple d'exécution serait le suivant.
>>> a = iter(InfIter())
>>> next(a)
1
>>> next(a)
3
>>> next(a)
5
>>> next(a)
7
Et ainsi de suite...
Veillez à inclure une condition de fin lors de l'itération sur ces types d'itérateurs infinis.
L'avantage d'utiliser des itérateurs est qu'ils économisent des ressources. Comme indiqué ci-dessus, nous pourrions obtenir tous les nombres impairs sans stocker le système de nombres entier en mémoire. Nous pouvons avoir des éléments infinis (théoriquement) dans une mémoire finie.
Il existe un moyen plus simple de créer des itérateurs en Python. Pour en savoir plus, consultez :Générateurs Python utilisant le rendement.
Python