Boucles Python "for" (Itération définie)

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 bouclewhile.

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 bouclesfor 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:

  • Initialisezi à1.

  • Continuez à boucler tant quei <= 10.

  • Incrémenteri 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 boucleforde 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é

iter()

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:

  • Appelleiter() pour obtenir un itérateur poura

  • Appellenext() à plusieurs reprises pour obtenir chaque élément de l'itérateur à son tour

  • Termine la boucle lorsquenext() 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.