Boucles Python "for" (Itération définie)
Ce didacticiel vous montrera comment exécuterdefinite iteration avec une boucle Pythonfor
.
Dans lesprevious tutorial de cette série d'introduction, vous avez appris ce qui suit:
-
L'exécution répétitive du même bloc de code à plusieurs reprises est appeléeiteration.
-
Il existe deux types d'itération:
-
ItérationDefinite, dans laquelle le nombre de répétitions est spécifié explicitement à l'avance
-
ItérationIndefinite, dans laquelle le bloc de code s'exécute jusqu'à ce qu'une condition soit remplie
-
-
En Python, une itération indéfinie est effectuée avec une boucle
while
.
Voici ce que vous allez aborder dans ce didacticiel:
-
Vous commencerez par une comparaison de différents paradigmes utilisés par les langages de programmation pour implémenter une itération définie.
-
Ensuite, vous découvrireziterables etiterators, deux concepts qui constituent la base d'une itération définie en Python.
-
Enfin, vous allez tout relier et découvrir les boucles
for
de Python.
Free Bonus:Click here to get access to a chapter from Python Tricks: The Book qui vous montre les meilleures pratiques de Python avec des exemples simples que vous pouvez appliquer instantanément pour écrire du code + Pythonic plus beau.
Une enquête sur l'itération définie dans la programmation
Les boucles d'itération définies sont fréquemment appelées bouclesfor
carfor
est le mot-clé utilisé pour les introduire dans presque tous les langages de programmation, y compris Python.
Historiquement, les langages de programmation ont offert quelques saveurs variées de bouclefor
. Celles-ci sont brièvement décrites dans les sections suivantes.
Boucle de plage numérique
La bouclefor
la plus élémentaire est une simple instruction de plage numérique avec des valeurs de début et de fin. Le format exact varie en fonction de la langue mais ressemble généralement à ceci:
for i = 1 to 10
Ici, le corps de la boucle est exécuté dix fois. La variablei
prend la valeur1
sur la première itération,2
sur la seconde, et ainsi de suite. Cette sorte de bouclefor
est utilisée dans les langages BASIC, Algol et Pascal.
Boucle à trois expressions
Une autre forme de bouclefor
popularisée par le langage de programmation C contient trois parties:
-
Une initialisation
-
Une expression spécifiant une condition de fin
-
Une action à effectuer à la fin de chaque itération.
Ce type de a la forme suivante:
for (i = 1; i <= 10; i++)
Technical Note: Dans le langage de programmation C,i++
incrémente la variablei
. C'est à peu près équivalent ài += 1
en Python.
Cette boucle est interprétée comme suit:
-
Initialisez
i
à1
. -
Continuez à boucler tant que
i <= 10
. -
Incrémenter
i
de1
après chaque itération de boucle.
Les boucles à trois expressionsfor
sont populaires parce que les expressions spécifiées pour les trois parties peuvent être presque n'importe quoi, donc cela a un peu plus de flexibilité que la forme de plage numérique plus simple montrée ci-dessus. Ces bouclesfor
sont également présentes dans les langages C ++, Java, PHP et Perl.
Boucle basée sur une collection ou basée sur un itérateur
Ce type de boucle parcourt une collection d'objets, plutôt que de spécifier des valeurs ou des conditions numériques:
for i in
A chaque fois dans la boucle, la variablei
prend la valeur de l'objet suivant en<collection>
. Ce type de bouclefor
est sans doute le plus généralisé et le plus abstrait. Perl et PHP supportent également ce type de boucle, mais il est introduit par le mot-cléforeach
au lieu defor
.
Further Reading: Consultez la page Wikipédia deFor loop pour un aperçu détaillé de l'implémentation de l'itération définie dans les langages de programmation.
La boucle de Pythonfor
Parmi les types de boucles répertoriés ci-dessus, Python implémente uniquement la dernière: itération basée sur la collection. À première vue, cela peut sembler brutal, mais soyez assuré que la mise en œuvre de Python de l'itération définitive est si polyvalente que vous ne vous sentirez pas trompé!
Bientôt, vous creuserez en détail les tripes de la bouclefor
de Python. Mais pour l'instant, commençons par un prototype et un exemple rapides, juste pour faire connaissance.
La bouclefor
de Python ressemble à ceci:
for in :
<iterable>
est une collection d'objets - par exemple, une liste ou un tuple. Les<statement(s)>
dans le corps de la boucle sont indiqués par indentation, comme avec toutes les structures de contrôle Python, et sont exécutés une fois pour chaque élément de<iterable>
. La variable de boucle<var>
prend la valeur de l'élément suivant en<iterable>
à chaque fois dans la boucle.
Voici un exemple représentatif:
>>>
>>> a = ['foo', 'bar', 'baz']
>>> for i in a:
... print(i)
...
foo
bar
baz
Dans cet exemple,<iterable>
est la listea
et<var>
est la variablei
. À chaque fois dans la boucle,i
prend un élément successif ena
, doncprint()
affiche les valeurs'foo'
,'bar'
et'baz'
, respectivement. Une bouclefor
comme celle-ci est la manière pythonique de traiter les éléments dans un itérable.
Mais qu'est-ce qu'un itérable exactement? Avant d'examiner plus en détail les bouclesfor
, il sera utile de se plonger plus profondément dans les itérables en Python.
Iterables
En Python,iterable signifie qu'un objet peut être utilisé dans l'itération. Le terme est utilisé comme:
-
An adjective: Un objet peut être décrit comme itérable.
-
A noun: Un objet peut être caractérisé comme un itérable.
Si un objet est itérable, il peut être passé à la fonction Python intégréeiter()
, qui renvoie quelque chose appeléiterator. Oui, la terminologie devient un peu répétitive. Accrochez-vous. Tout fonctionne à la fin.
Chacun des objets de l'exemple suivant est un itérable et renvoie un type d'itérateur lorsqu'il est passé àiter()
:
>>>
>>> iter('foobar') # String
>>> iter(['foo', 'bar', 'baz']) # List
>>> iter(('foo', 'bar', 'baz')) # Tuple
>>> iter({'foo', 'bar', 'baz'}) # Set
>>> iter({'foo': 1, 'bar': 2, 'baz': 3}) # Dict
En revanche, ces types d'objets ne sont pas itérables:
>>>
>>> iter(42) # Integer
Traceback (most recent call last):
File "", line 1, in
iter(42)
TypeError: 'int' object is not iterable
>>> iter(3.1) # Float
Traceback (most recent call last):
File "", line 1, in
iter(3.1)
TypeError: 'float' object is not iterable
>>> iter(len) # Built-in function
Traceback (most recent call last):
File "", line 1, in
iter(len)
TypeError: 'builtin_function_or_method' object is not iterable
Tous les types de données que vous avez rencontrés jusqu'à présent qui sont des types de collection ou de conteneur sont itérables. Ceux-ci incluent les typesstring,list,tuple,dict,set etfrozenset.
Mais ce ne sont en aucun cas les seuls types sur lesquels vous pouvez répéter. De nombreux objets intégrés à Python ou définis dans des modules sont conçus pour être itérables. Par exemple, les fichiers ouverts en Python sont itérables. Comme vous le verrez bientôt dans le didacticiel sur les E / S de fichiers, l'itération sur un objet fichier ouvert lit les données du fichier.
En fait, presque n'importe quel objet en Python peut être rendu itérable. Même les objets définis par l'utilisateur peuvent être conçus de manière à pouvoir être itérés. (Vous découvrirez comment cela se fait dans le prochain article sur la programmation orientée objet.)
Itérateurs
Bon, maintenant vous savez ce que cela signifie pour un objet d'être itérable, et vous savez comment utiliseriter()
pour en obtenir un itérateur. Une fois que vous avez un itérateur, que pouvez-vous en faire?
Un itérateur est essentiellement un producteur de valeur qui génère des valeurs successives à partir de son objet itérable associé. La fonction intégréenext()
est utilisée pour obtenir la valeur suivante à partir de l'itérateur.
Voici un exemple utilisant la même liste que ci-dessus:
>>>
>>> a = ['foo', 'bar', 'baz']
>>> itr = iter(a)
>>> itr
>>> next(itr)
'foo'
>>> next(itr)
'bar'
>>> next(itr)
'baz'
Dans cet exemple,a
est une liste itérable etitr
est l'itérateur associé, obtenu aveciter()
. Chaque appel denext(itr)
obtient la valeur suivante deitr
.
Remarquez comment un itérateur conserve son état en interne. Il sait quelles valeurs ont déjà été obtenues, donc lorsque vous appeleznext()
, il sait quelle valeur renvoyer ensuite.
Que se passe-t-il lorsque l'itérateur manque de valeurs? Faisons un autre appelnext()
sur l'itérateur ci-dessus:
>>>
>>> next(itr)
Traceback (most recent call last):
File "", line 1, in
next(itr)
StopIteration
Si toutes les valeurs d'un itérateur ont déjà été renvoyées, un appel denext()
suivant lève une exceptionStopIteration
. Toute autre tentative pour obtenir des valeurs de l'itérateur échouera.
Vous ne pouvez obtenir des valeurs d'un itérateur que dans une seule direction. Vous ne pouvez pas revenir en arrière. Il n'y a pas de fonctionprev()
. Mais vous pouvez définir deux itérateurs indépendants sur le même objet itérable:
>>>
>>> a
['foo', 'bar', 'baz']
>>> itr1 = iter(a)
>>> itr2 = iter(a)
>>> next(itr1)
'foo'
>>> next(itr1)
'bar'
>>> next(itr1)
'baz'
>>> next(itr2)
'foo'
Même lorsque l'itérateuritr1
est déjà à la fin de la liste,itr2
est toujours au début. Chaque itérateur maintient son propre état interne, indépendant de l'autre.
Si vous voulez récupérer toutes les valeurs d'un itérateur à la fois, vous pouvez utiliser la fonction intégréelist()
. Parmi les autres utilisations possibles,list()
prend un itérateur comme argument et renvoie une liste comprenant toutes les valeurs que l'itérateur a fournies:
>>>
>>> a = ['foo', 'bar', 'baz']
>>> itr = iter(a)
>>> list(itr)
['foo', 'bar', 'baz']
De même, les fonctions intégréestuple()
etset()
renvoient un tuple et un ensemble, respectivement, à partir de toutes les valeurs qu'un itérateur donne:
>>>
>>> a = ['foo', 'bar', 'baz']
>>> itr = iter(a)
>>> tuple(itr)
('foo', 'bar', 'baz')
>>> itr = iter(a)
>>> set(itr)
{'baz', 'foo', 'bar'}
Il n'est pas forcément conseillé de prendre l'habitude de cela. Une partie de l'élégance des itérateurs est qu'ils sont «paresseux». Cela signifie que lorsque vous créez un itérateur, il ne génère pas tous les éléments qu'il peut générer à ce moment-là. Il attend que vous les demandiez avecnext()
. Les éléments ne sont créés que lorsqu'ils sont demandés.
Lorsque vous utilisezlist()
,tuple()
ou similaire, vous forcez l'itérateur à générer toutes ses valeurs à la fois, afin qu'elles puissent toutes être renvoyées. Si le nombre total d'objets retournés par l'itérateur est très élevé, cela peut prendre du temps.
En fait, il est possible de créer un itérateur en Python qui renvoie une série infinie d'objets. (Vous apprendrez comment faire cela dans les prochains tutoriels sur les fonctions du générateur et lesitertools
.) Si vous essayez de récupérer toutes les valeurs à la fois à partir d'un itérateur sans fin, le programme ferahang.
Les entrailles de la boucle Pythonfor
Vous avez maintenant découvert tous les concepts dont vous avez besoin pour bien comprendre le fonctionnement de la bouclefor
de Python. Avant de poursuivre, examinons les termes pertinents:
Term | Sens |
---|---|
Itération |
Le processus de lecture en boucle des objets ou des éléments d'une collection |
Iterable |
Un objet (ou l'adjectif utilisé pour décrire un objet) qui peut être itéré sur |
Itérateur |
L'objet qui produit des éléments ou des valeurs successifs à partir de son itérable associé |
|
La fonction intégrée utilisée pour obtenir un itérateur à partir d'un itérable |
Maintenant, considérons à nouveau la simple bouclefor
présentée au début de ce tutoriel:
>>>
>>> a = ['foo', 'bar', 'baz']
>>> for i in a:
... print(i)
...
foo
bar
baz
Cette boucle peut être entièrement décrite en termes de concepts que vous venez d'apprendre. Pour effectuer l'itération décrite par cette bouclefor
, Python effectue les opérations suivantes:
-
Appelle
iter()
pour obtenir un itérateur poura
-
Appelle
next()
à plusieurs reprises pour obtenir chaque élément de l'itérateur à son tour -
Termine la boucle lorsque
next()
lève l'exceptionStopIteration
Le corps de la boucle est exécuté une fois pour chaque élémentnext()
renvoie, avec la variable de bouclei
définie sur l'élément donné pour chaque itération.
Cette séquence d'événements est résumée dans le diagramme suivant:
Peut-être que cela semble être une affaire de singe inutile, mais l'avantage est substantiel. Python traite le bouclage sur tous les itérables exactement de cette manière, et en Python, les itérables et les itérateurs abondent:
-
De nombreux objets intégrés et de bibliothèque sont itérables.
-
Il existe un module de bibliothèque standard appelé
itertools
contenant de nombreuses fonctions qui renvoient des itérables. -
Les objets définis par l'utilisateur créés avec la capacité orientée objet de Python peuvent être rendus itérables.
-
Python propose une construction appelée générateur qui vous permet de créer votre propre itérateur de manière simple et directe.
Vous découvrirez plus sur tout ce qui précède tout au long de cette série. Ils peuvent tous être la cible d'une bouclefor
, et la syntaxe est la même partout. Il est élégant dans sa simplicité et éminemment polyvalent.
Itération dans un dictionnaire
Vous avez vu précédemment qu'un itérateur peut être obtenu à partir d'un dictionnaire aveciter()
, vous savez donc que les dictionnaires doivent être itérables. Que se passe-t-il lorsque vous parcourez un dictionnaire? Voyons voir:
>>>
>>> d = {'foo': 1, 'bar': 2, 'baz': 3}
>>> for k in d:
... print(k)
...
foo
bar
baz
Comme vous pouvez le voir, lorsqu'une bouclefor
parcourt un dictionnaire, la variable de boucle est affectée aux clés du dictionnaire.
Pour accéder aux valeurs du dictionnaire dans la boucle, vous pouvez créer une référence de dictionnaire en utilisant la clé comme d'habitude:
>>>
>>> for k in d:
... print(d[k])
...
1
2
3
Vous pouvez également parcourir les valeurs d’un dictionnaire directement en utilisant.values()
:
>>>
>>> for v in d.values():
... print(v)
...
1
2
3
En fait, vous pouvez parcourir simultanément les clés et les valeurs d'un dictionnaire. En effet, la variable de boucle d’une bouclefor
n’est pas limitée à une seule variable. Il peut également s'agir d'un tuple, auquel cas les affectations sont effectuées à partir des éléments de l'itérable à l'aide de l'emballage et du déballage, tout comme avec une instruction d'affectation:
>>>
>>> i, j = (1, 2)
>>> print(i, j)
1 2
>>> for i, j in [(1, 2), (3, 4), (5, 6)]:
... print(i, j)
...
1 2
3 4
5 6
Comme indiqué dans le tutoriel sur Pythondictionaries, la méthode du dictionnaire.items()
renvoie effectivement une liste de paires clé / valeur sous forme de tuples:
>>>
>>> d = {'foo': 1, 'bar': 2, 'baz': 3}
>>> d.items()
dict_items([('foo', 1), ('bar', 2), ('baz', 3)])
Ainsi, la façon Pythonic d'itérer à travers un dictionnaire accédant à la fois aux clés et aux valeurs ressemble à ceci:
>>>
>>> d = {'foo': 1, 'bar': 2, 'baz': 3}
>>> for k, v in d.items():
... print('k =', k, ', v =', v)
...
k = foo , v = 1
k = bar , v = 2
k = baz , v = 3
La fonctionrange()
Dans la première section de ce didacticiel, vous avez vu un type de bouclefor
appelénumeric range loop, dans lequel des valeurs numériques de début et de fin sont spécifiées. Bien que cette forme de bouclefor
ne soit pas directement intégrée à Python, elle est facilement accessible.
Par exemple, si vous souhaitez parcourir les valeurs de0
à4
, vous pouvez simplement faire ceci:
>>>
>>> for n in (0, 1, 2, 3, 4):
... print(n)
...
0
1
2
3
4
Cette solution n'est pas trop mauvaise quand il n'y a que quelques chiffres. Mais si la plage de nombres était beaucoup plus grande, cela deviendrait assez fastidieux.
Heureusement, Python fournit une meilleure option - la fonction intégréerange()
, qui renvoie un itérable qui produit une séquence d'entiers.
range(<end>)
renvoie un itérable qui donne des entiers commençant par0
, jusqu'à mais non compris<end>
:
>>>
>>> x = range(5)
>>> x
range(0, 5)
>>> type(x)
Notez querange()
renvoie un objet de la classerange
, pas une liste ou un tuple des valeurs. Étant donné qu'un objetrange
est un itérable, vous pouvez obtenir les valeurs en les parcourant avec une bouclefor
:
>>>
>>> for n in x:
... print(n)
...
0
1
2
3
4
Vous pouvez également accrocher toutes les valeurs à la fois aveclist()
outuple()
. Dans une session REPL, cela peut être un moyen pratique d'afficher rapidement les valeurs:
>>>
>>> list(x)
[0, 1, 2, 3, 4]
>>> tuple(x)
(0, 1, 2, 3, 4)
Cependant, lorsquerange()
est utilisé dans du code qui fait partie d'une application plus large, il est généralement considéré comme une mauvaise pratique d'utiliserlist()
outuple()
de cette manière. Comme les itérateurs, les objetsrange
sont paresseux - les valeurs de la plage spécifiée ne sont générées que lorsqu'elles sont demandées. L'utilisation delist()
outuple()
sur un objetrange
force toutes les valeurs à être renvoyées en même temps. C'est rarement nécessaire, et si la liste est longue, cela peut perdre du temps et de la mémoire.
range(<begin>, <end>, <stride>)
renvoie un itérable qui produit des entiers commençant par<begin>
, jusqu'à mais non compris<end>
. Si spécifié,<stride>
indique une quantité à sauter entre les valeurs (analogue à la valeur de pas utilisée pour le découpage de chaînes et de listes):
>>>
>>> list(range(5, 20, 3))
[5, 8, 11, 14, 17]
Si<stride>
est omis, la valeur par défaut est1
:
>>>
>>> list(range(5, 10, 1))
[5, 6, 7, 8, 9]
>>> list(range(5, 10))
[5, 6, 7, 8, 9]
Tous les paramètres spécifiés àrange()
doivent être des entiers, mais n'importe lequel d'entre eux peut être négatif. Naturellement, si<begin>
est supérieur à<end>
,<stride>
doit être négatif (si vous voulez des résultats):
>>>
>>> list(range(-5, 5))
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]
>>> list(range(5, -5))
[]
>>> list(range(5, -5, -1))
[5, 4, 3, 2, 1, 0, -1, -2, -3, -4]
Technical Note: À proprement parler,range()
n’est pas exactement une fonction intégrée. Il est implémenté en tant que classe appelable qui crée un type de séquence immuable. Mais à des fins pratiques, il se comporte comme une fonction intégrée.
Pour plus d'informations surrange()
, consultez l'articlePython’s range()
Function (Guide) sur Real Python.
Modification du comportement de la bouclefor
Vous avez vu dans le tutoriel précédent de cette série d'introduction comment l'exécution d'une bouclewhile
peut être interrompue avecbreak
and continue
statements et modifiée avec unelse
clause. Ces capacités sont également disponibles avec la bouclefor
.
Les instructionsbreak
etcontinue
break
etcontinue
fonctionnent de la même manière avec les bouclesfor
qu'avec les boucleswhile
. break
termine complètement la boucle et passe à la première instruction suivant la boucle:
>>>
>>> for i in ['foo', 'bar', 'baz', 'qux']:
... if 'b' in i:
... break
... print(i)
...
foo
continue
termine l'itération en cours et passe à l'itération suivante:
>>>
>>> for i in ['foo', 'bar', 'baz', 'qux']:
... if 'b' in i:
... continue
... print(i)
...
foo
qux
La clauseelse
Une bouclefor
peut également avoir une clauseelse
. L'interprétation est analogue à celle d'une bouclewhile
. La clauseelse
sera exécutée si la boucle se termine par épuisement de l'itérable:
>>>
>>> for i in ['foo', 'bar', 'baz', 'qux']:
... print(i)
... else:
... print('Done.') # Will execute
...
foo
bar
baz
qux
Done.
La clauseelse
ne sera pas exécutée si la liste est interrompue avec une instructionbreak
:
>>>
>>> for i in ['foo', 'bar', 'baz', 'qux']:
... if i == 'bar':
... break
... print(i)
... else:
... print('Done.') # Will not execute
...
foo
Conclusion
Ce tutoriel a présenté la bouclefor
, le cheval de bataille dedefinite iteration en Python.
Vous avez également découvert le fonctionnement interne deiterables etiterators, deux types d'objets importants qui sous-tendent une itération définie, mais qui figurent également en bonne place dans une grande variété d'autres codes Python.
Dans les deux prochains didacticiels de cette série d'introduction, vous allez un peu changer de vitesse et explorer comment les programmes Python peuvent interagir avec l'utilisateur viainput depuis le clavier etoutput vers la console.