Séance 2#
Objectifs
Listes
Boucles
Compléments sur les fonctions
Listes#
Création et accès#
Les listes sont des structures de données permettant de stocker différentes valeurs dans un ordre précis. Une liste est représentée par des crochets [, ] entre lequels on place des éléments séparés par des virgules. Les éléments d’une même liste peuvent être de différentes natures : cela peut être des entiers, des flottants, des chaînes de caractères, et même d’autres listes.
Question. Créer la liste des cinq premières lettres de l’alphabet, et l’affecter à la variable L.
L = ["a", "b", "c", "d", "e"]
print(L)
['a', 'b', 'c', 'd', 'e']
En python, le premier élément d’une liste a pour indice \(0\). Si une liste contient \(n\) éléments, le dernier élément a donc pour indice \(n-1\). Par ailleurs, on accède à l’élément d’indice \(i\) d’une liste L par L[i].
Question. Afficher le premier élément de la liste L, puis l’élément d’indice \(3\) de la liste L.
print(L[0])
print(L[3])
a
d
Attention à ne pas essayer d’accéder à un élément qui n’existe pas !
L[5]
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
Cell In[3], line 1
----> 1 L[5]
IndexError: list index out of range
Dans le message d’erreur, python nous explique le problème : « erreur d’indice : indice de liste hors de portée ». En général, lisez bien les messages d’erreur, il vous renseignent sur le problème !
Pour ne pas se tromper sur le dernier élément, la fonction len permet de retourner la longueur d’une liste :
len(L)
5
Remarque. Il existe également une liste vide, représentée par []. Sa longueur est nulle.
len([])
0
Comme pour les chaînes de caractères, on peut concaténer deux listes avec l’opération +, et répéter plusieurs fois la même liste avec l’opération *.
M = [1, 2]
print(L + M)
print(M * 6)
['a', 'b', 'c', 'd', 'e', 1, 2]
[1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2]
Modification, suppression et insertion#
On peut également modifier le contenu d’une liste préexistante, par exemple en remplaçant la valeur L[i] stockée à un certain indice i par une autre valeur v. Pour cela, on affecte simplement la valeur à la « case mémoire » : on écrit L[i] = v.
Question. Remplacer le \(2\)-ème élément de la liste L par l’entier \(0\), puis afficher L.
L[1] = 0
print(L)
['a', 0, 'c', 'd', 'e']
Pour ajouter un élément en fin de liste, on peut utiliser la méthode de liste nommée append. Une méthode est une fonction attachée à un objet. On y accède par un point . qui sépare l’objet (avant) et la méthode (après). Généralement, on écrit donc
<objet>.<methode>(<arguments>)
Ainsi, pour ajouter la chaîne de caractères « nouveau » à la fin de la liste L, on écrit :
L.append("nouveau")
print(L)
['a', 0, 'c', 'd', 'e', 'nouveau']
Remarque. La méthode append n’a pas de valeur de retour. Elle ne fait que modifier la liste L. Ainsi, on n’écrira pas L = L.append(x).
Pour retirer le dernier élément d’une liste, on utilise la méthode pop. Cette méthode modifie la liste, et a comme valeur de retour la valeur retirée.
Question. Retirer le dernier élément de la liste L et le stocker dans x.
x = L.pop()
print(x)
print(L)
nouveau
['a', 0, 'c', 'd', 'e']
La méthode pop peut être utilisée pour retirer de la liste un élément d’indice quelconque. Pour cela, on place cet indice i comme argument de la méthode : on écrit L.pop(i).
M = [1, 2, 3]
x = M.pop(1)
print(M)
[1, 3]
Remarque. La méthode pop peut donc être utilisée avec ou sans argument ; on parle d’argument optionnel.
Il est également possible d’insérer des éléments dans une liste, à une position particulière. La méthode correspondante est insert. Elle prend en entrée deux arguments :
la position d’insertion (nommons-la
position), qui est un entier entre \(0\) et la longueur de la liste ;la valeur à insérer (nommons-la
valeur) qui est un élément quelconque. Pour un listeL, la syntaxe pour l’insertion est alorsL.insert(position, valeur).
Question. Insérer le mot « insertion » en troisième position de la liste L.
L.insert(2, "insertion")
print(L)
['a', 0, 'insertion', 'c', 'd', 'e']
Tableau récapitulatif.
Opération sur la liste |
Syntaxe python |
|---|---|
Longueur |
|
Concaténation |
|
Accès à l’élément d’indice \(i\) |
|
Modification à la position \(i\) |
|
Ajout en fin de liste |
|
Insertion à la position \(i\) |
|
Suppression et accès (première position) |
|
Suppression et accès (position générale) |
|
Boucles#
Python permet de créer des boucles, c’est-à-dire une succession d’instructions à répéter. La répétition de ces instructions peut être paramètrée par une valeur ou par un test.
Il existe deux formes principales de boucles :
les boucles
for, qui permettent d’effectuer la série d’instructions pour certaines valeurset les boucles
while, qui permettent d’effectuer la série d’instructions tant qu” une certaine condition est vérifiée. Dans les deux cas, les instructions à répéter doivent être indentées (utiliser la touche « TAB »).
Boucle for#
Pour la boucle for, on utilise la syntaxe
for <variable> in <structure>:
<instruction1>
<instruction2>
<instruction3>
où <structure> peut-être, par exemple, une liste, une chaîne de caractères ou généralement un objet qu’on qualifie d”itérable (nous verrons cela par la suite). La variable <variable> est créée lors de l’initialisation de la boucle, et prend successivement comme valeur celle des éléments de <structure>. Attention : si la variable existe déjà, sa valeur antérieure sera écrasée !
Questions. Déclarer une liste L contenant les chaînes de caractères associées aux lettres « a », « b » et « c ». Puis, avec une boucle for, afficher successivement les éléments de cette liste.
L = ["a", "b", "c"]
for x in L:
print(x)
a
b
c
Question. Avec une boucle for et une liste judicieusement créée, faire la somme des entiers de \(2\) à \(6\).
somme = 0
for i in [2, 3, 4, 5, 6]:
somme = somme + i
print(somme)
20
Si l’on souhaitait faire la somme des entiers de \(2\) à \(10000\), on ne voudrait pas avoir à créer à la main la liste [2, 3, 4, ..., 10000]. Pour nous aider, le mot-clef range permet de décrire une suite arithmétique entière sous la forme d’un itérateur (ce n’est pas vraiment une liste). Ce mot-clef est particulièrement utile lorsqu’on souhaite parcourir tous les entiers entre a (inclus) et b (non-inclus). Pour cela, on écrit range(a, b).
Question. Même question que la précédente, mais sans la liste, et avec le mot-clef range.
somme = 0
for i in range(2,7):
somme += i
somme
20
Si le premier paramètre a vaut \(0\), alors on peut l’omettre et écrire plus simplement range(b).
Question. Même question en partant de l’entier \(0\).
somme = 0
for i in range(7):
somme += i
somme
21
Le mot-clef range permet aussi de décrire les éléments d’une suite arithmétique d’entiers. Dans sa forme la plus générale, range prend ainsi comme paramètres trois entiers relatifs a, b et c. Dans ce cas, range(a, b, c) retourne la séquence d’entiers : \(a\), \(a+c\), \(a+2c\), …, \(a +ic\), où \(a+ic\) est le dernier terme de la suite qui n’atteint pas la valeur \(b\). Par exemple, range(-1, 7, 2) parcourt les éléments \(-1\), \(1\), \(3\) et \(5\), tandis que range(6, 2, -1) parcourt les éléments \(6\), \(5\), \(4\) et \(3\).
Lorsque c vaut \(1\), on peut simplement écrire range(a, b), et lorsque c vaut \(1\) et a vaut \(0\), on peut écrire range(b).
Un autre exemple :
for i in range(-4, 8, 3):
print(i)
-4
-1
2
5
Boucle while#
Une boucle while a la syntaxe suivante :
while <valeur_booleenne>:
<instruction1>
<instruction2>
<instruction3>
où <valeur_booleenne> est, comme son nom l’indique, une valeur booléenne le plus souvent issue d’un test logique. Les instructions se répètent tant que la valeur booléenne est vraie. Attention : si cette valeur n’est jamais fausse, la boucle va être répétée à l’infini !
Question. Reprendre les questions précédentes avec une boucle while.
L = ["a", "b", "c"]
i = 0
while (i < len(L)):
print(L[i])
i += 1
a
b
c
somme = 0
i = 2
while (i < 7):
somme = somme + i
i += 1
somme
20
somme = 0
i = 0
while (i < 7):
somme = somme + i
i += 1
somme
21
Fonctions récursives#
Dans le chapitre précédent, nous avons vu comme créer des fonctions simples et comment les appeler. Les fonctions peuvent s’appeler elles-mêmes : on parle de fonction récursive.
def compte_a_rebours(n):
if (n == 0):
print("Départ")
else:
print(n)
compte_a_rebours(n-1)
compte_a_rebours(5)
5
4
3
2
1
Départ
Il assez naturel d’utiliser des fonctions récursives pour implanter des calculs de nature récursive sur des objets. On peut penser par exemple au calcul du \(n\)-ème terme d’une suite récurrente simple.
Question. Supposons que \((u_n)_n\) soit définie par \(u_0 = 2\) et \(u_n = n u_{n-1} - 3 (n-1)^2\) pour tout \(n \ge 0\). Écrire une fonction récursive calcule_u(n) qui calcule le terme d’ordre \(n\) de la suite \((u_n)_n\).
def calcule_u(n):
if (n == 0):
return 2
else:
return n * calcule_u(n-1) - 3 * (n-1)**2
calcule_u(5)
-363
Passage par valeur ou par adresse#
Lorsque l’on passe une variable comme argument d’une fonction, python réalise une copie « locale » de la variable qui sera utilisée lors du temps de l’exécution de la fonction.
Ainsi, lorsqu’un entier passé en paramètre d’une fonction est modifié, on a le comportement suivant :
def carre(n):
n = n**2
print("Dans l'appel de fonction, n =", n)
return n
n = 2
print("Avant l'appel de fonction, n =", n)
c = carre(n)
print("Après l'appel de fonction, n =", n)
Avant l'appel de fonction, n = 2
Dans l'appel de fonction, n = 4
Après l'appel de fonction, n = 2
C’est donc la copie de n, interne à la fonction carre, qui est modifiée. On parle de passage par valeur du paramètre de la fonction.
Si le paramètre de la fonction est une liste, le comportement est différent. En effet, une liste est définie par une adresse mémoire qui « pointe » vers des données (les éléments de la liste). Lors de l’appel de la fonction, la copie de l’adresse mémoire de la liste donne donc accès aux mêmes éléments que la liste initiale. Toute modification de la liste dans la fonction s’observera donc hors de la fonction. On parle de passage du paramètre par adresse. Voici un comportement typique :
def avant_dernier_element(L):
L.pop()
x = L.pop()
print("Dans l'appel de fonction, L =", L)
return x
L = [1, 2, 3, 4, 5]
print("Avant l'appel de fonction, L =", L)
x = avant_dernier_element(L)
print("Après l'appel de fonction, L =", L)
print("Avant-dernier élément :", x)
Avant l'appel de fonction, L = [1, 2, 3, 4, 5]
Dans l'appel de fonction, L = [1, 2, 3]
Après l'appel de fonction, L = [1, 2, 3]
Avant-dernier élément : 4
Avertissement
Attention, réaffecter la liste à une autre variable ne résout pas le problème ! En effet, l’affectation M = L ne fait que copier l’adresse mémoire de la liste L dans la variable M. Pour faire une copie « dure » de la liste, il faut utiliser M = L.copy()