Un tableau est un type de donnée permettant de stocker plusieurs valeurs de manière séquentielle et d’y accéder à l’aide d’une seule variable.
Le moyen le plus simple de créer un tableau en python est d’énumérer l’ensemble de ses valeurs:
>>> table = [1, 0, 5, -2, 4,]
>>> table
[1, 0, 5, -2, 4]
On vient ici de créer une variable table
qui est un tableau (toute énumération de valeurs entre crochets [ ]
sera interprétée comme un tableau par python).
Voyez ce qu’il se passe en sous-main à l’aide de python tutor:
table
. Pour accéder à la valeur d’indice i
, on utilise la syntaxe table[i]
:
>>> table[0]
1
>>> table[1]
0
>>> table[2]
5
>>> table[3]
-2
>>> table[4]
5
Notons que le dernier élément du tableau a pour indice 4 alors que le tableau contient 5 éléments. C’est tout à fait normal: de 0 à 4, il y a exactement 5 valeurs.
On peut connaître le nombre d’éléments d’un tableau à l’aide de la fonction len()
:
>>> len(table)
5
Attention, il n’est pas possible d’accéder à un élément dont l’indice serait supérieur au dernier indice, c’est-à-dire à la longeur moins 1. En particulier, table[len(table)]
n’existe pas et provoquera une erreur.
Point très important: Le langage python autorise à stocker dans un tableau des données de type quelconque, sans aucune cohérence: on peut mettre des entiers, des nombres à virgule flottante, des chaînes de caractères… dans un même tableau.
>>> mélange = ["pomme", 12, 3.14, "pêche"] >>> mélange ["pomme", 12, 3.14, "pêche"]
Cependant, la plupart des autres langages n’autorisent pas ce genre de lattitude: un tableau ne peut contenir qu’un type unique de données.
Afin d’éviter la prise de mauvaises habitudes, on s’astreindra à partir de maintenant à ne jamais utiliser de tableau contenant des données mixtes.
Il n’est pas envisageable d’énumérer à la main tous les éléments d’un tableau comme nous avons pu le faire dans un exemple précédent, d’autant plus que le nombre d’éléments du tableau peut fort bien varier au cours de la durée de vie d’un programme.
On utilisera avantageusement une boucle (pour ou tant que) afin d’accéder à l’ensemble des éléments d’un tableau.
Plusieurs cas de figure se présentent, selon que l’on souhaite connaître l’indice d’un élément donné ou non.
Dans ce cas, la boucle pour est de loin la plus adaptée. La syntaxe de cette boucle est d’ailleurs exactement conçue pour accéder aux éléments d’un tableau:
prénoms = ["pascal", "pierre", "bérénice", "isabelle", "mathieu", "joachim", "anabelle"]
for p in prénoms:
print(p)
Le résultat sera:
pascal
pierre
bérénice
isabelle
mathieu
joachim
anabelle
Dans ce cas il existe plusieurs méthodes. On peut réutiliser la boucle précédente et compter les indices à la main:
i = 0
for p in prénoms:
print("Le prénom d'incice", i, "est", p)
i = i + 1
Le prénom d'incice 0 est pascal
Le prénom d'incice 1 est pierre
Le prénom d'incice 2 est bérénice
Le prénom d'incice 3 est isabelle
Le prénom d'incice 4 est mathieu
Le prénom d'incice 5 est joachim
Le prénom d'incice 6 est anabelle
Notons qu’il est indispensable d’incrémenter à la main le compteur.
On peut aussi procéder autrement, en faisant boucler directement sur l’indice i
plutôt que sur l’élément p
. Il faudra dans ce cas utiliser la syntaxe suivante:
for i in range(len(prénoms)):
print("Le prénom d'indice", i, "est", prénoms[i])
Le prénom d'indice 0 est pascal
Le prénom d'indice 1 est pierre
Le prénom d'indice 2 est bérénice
Le prénom d'indice 3 est isabelle
Le prénom d'indice 4 est mathieu
Le prénom d'indice 5 est joachim
Le prénom d'indice 6 est anabelle
Le résultat est exactement le même, mais l’algorithme sous–jacent bien différent: on utiliser la fonction range()
avec pour paramètre la longueur len(prénoms)
du tableau: la variable i
parcourera donc bien les entiers de 0
à len(prénoms) - 1
. Pour accéder à l’élément du tableau correspondant, on utilise alors la syntaxe prénoms[i]
vue dans la partie précédente.
Notons qu’il n’est pas nécessaire ici d’incrémenter le compteur, c’est la boucle pour qui s’en charge.
On pourrait aussi remplacer celle-ci par une boucle tant que:
i = 0
while i < len(prénoms):
print("Le prénom d'indice", i, "est", prénoms[i])
i = i + 1
Le prénom d'indice 0 est pascal
Le prénom d'indice 1 est pierre
Le prénom d'indice 2 est bérénice
Le prénom d'indice 3 est isabelle
Le prénom d'indice 4 est mathieu
Le prénom d'indice 5 est joachim
Le prénom d'indice 6 est anabelle
Cela paraît plus compliqué parce qu’on est à nouveau obligé d’incrémenter le compteur, mais la boucle tant que offre d’autres avantages: on peut utiliser une condition plus compliquée, arrêter le parcours du tableau avant la fin (par exemple lorsque l’on aura trouvé un élément que l’on recherche). Nous verrons cela en exercice.
En python, un tableau n’est pas une structure figée en mémoire. On peut notamment:
Nous ne verrons pas toutes ces possibilités dans un premier temps, mais examinons les plus courantes.
Pour modifier un élément dans un tableau, on utilise la syntaxe suivante:
>>> prénoms
['pascal', 'pierre', 'bérénice', 'isabelle', 'mathieu', 'joachim', 'anabelle']
>>> prénoms[1] = 'archibald'
>>> prénoms
['pascal', 'archibald', 'bérénice', 'isabelle', 'mathieu', 'joachim', 'anabelle']
On constate que le contenu du tableau a bien été modifié: son deuxième élément (donc d’indice 1) a été remplacé par un autre. On dit en informatique qu’un tableau est une donnée variable, c’est-à-dire que son contenu peut être modifié en mémoire (ce n’est pas toujours le cas, comme nous le verrons plus tard, il y a aussi en python des données immuables comme par exemple les chaînes de caractères).
L’ajout d’élements n’est pas la même chose que la modification d’un élément vue au paragraphe précédent: le contenu d’une des cases mémoire était simplement remplacé par un autre, alors qu’ici nous voulons modifier la taille du tableau. Python est extrêmement souple sur ce point, et autorise tous les changements de taille, tant qu’il reste de la mémoire disponible.
Pour ajouter un unique élément à un tableau, on peut utiliser la fonction append(élément)
appliquée directement au tableau, comme suit:
>>> prénoms
['pascal', 'pierre', 'bérénice', 'isabelle', 'mathieu', 'joachim', 'anabelle']
>>> prénoms.append('maximilien')
>>> prénoms
['pascal', 'pierre', 'bérénice', 'isabelle', 'mathieu', 'joachim', 'anabelle', 'maximilien']
On constate que la fonction append(donnée)
ne renvoie aucune valeur significative. Par contre elle agit bien sur le tableau, et en modifie la structure. On dit que append
est une fonction qui possède un effet de bord (c’est-à-dire que son but n’est pas de renvoyer une valeur, mais d’affecter son environnement, ici la mémoire de l’ordinateur).
Pour supprimer le dernier élément d’un tableau, il y a la fonction pop()
(sans arguments): celle-ci supprime effectivement l’élément de plus grand indice, et renvoie sa valeur. Attention, pop()
utilisé sur un tableau vide []
renverra une erreur puisqu’il n’y a pas d’élément à supprimer.
>>> prénoms.pop()
'maximilien'
>>> prénoms
['pascal', 'pierre', 'bérénice', 'isabelle', 'mathieu', 'joachim', 'anabelle']
Nous constatons que pop()
a bien renvoyé la valeur du dernier élément du tableau, et l’a effacé de celui-ci: c’est une fonction à effet de bord, qui renvoie en outre une valeur intéressante.
On a souvent besoin de prendre deux tableaux et de les concaténer, c’est-à-dire les mettre bout à bout. Il existe deux manière de procéder en python.
Supposons que l’on ait deux tableaux:
>>> t1 = [1, 2, 3, 4]
>>> t2 = [5, 6, 7, 8]
L’opération +
entre deux tableaux ne réalise pas une addition (cela n’aurait aucun sens), mais crée un nouveau tableau contenant la concaténation des deux premiers. Il est important de remarquer qu’aucun des deux tableaux initiaux n’est modifié par cette opération.
>>> t1 + t2
[1, 2, 3, 4, 5, 6, 7, 8]
>>> t1
[1, 2, 3, 4]
>>> t2
[5, 6, 7, 8]
Observez ces manipulations basiques à l’aide de python tutor.
Si on ne veut pas perdre immédiatement le résultat de t1 + t2
, il est tout à fait possible de le stocker dans une nouvelle variable, voire même dans une variable existante. Par exemple, on peut vouloir remplacer t1
par la concaténation de t1
et t2
, comme suit:
>>> t1 = t1 + t2
>>> t1
[1, 2, 3, 4, 5, 6, 7, 8]
>>> t2
[5, 6, 7, 8]
Observez cette différence fondamentale de comportement par rapport à l’exécution dynamique précédente: python tutor.
Il est possible de réaliser directement l’opération précédente à l’aide de la fonction extend(tableau)
:
>>> t1 = [1, 2, 3, 4]
>>> t2 = [5, 6, 7, 8]
>>> t1.extend(t2)
>>> t1
[1, 2, 3, 4, 5, 6, 7, 8]
>>> t2
[5, 6, 7, 8]
Le résultat semble être le même que pour la syntaxe t1 = t1 + t2
précédente, mais ce n’est pas exactement le cas: extend()
va modifier le tableau t1
pour lui rajouter directement les éléments de t2
(un peu comme si on avait utilisé append
pour chacun des éléments de t2
sur t1
). En revanche, t1 = t1 + t2
crée d’abord un nouveau tableau, qui est ensuite stocké dans t1
. L’ancien tableau qui était dans t1
n’étant plus référencé par aucune variable, il sera effacé de la mémoire par python dès que possible.
Pour ce rendre compte de cette différence fondamentale, examinons une situation où une autre variable pointe sur même tableau que t1
:
Déroulé avec python tutor lorsque l’on utilise la concaténation par l’opérateur +
.
Après avoir créé la variable copie_t1
pointant sur le même tableau que t1
, on observe très clairement le partage des données en mémoire (il est très courant que plusieurs variables pointent sur une même valeur, mais comme nous allons le voir, ce n’est pas sans dangers).
Après avoir exécuté la ligne t1 = t1 + t2
, la variable t1
pointe bien sur la concaténation des deux tableaux, mais la variable copie_t1
est restée sur sa valeur initiale (c’est probablement ce que l’on souhaitait obtenir de toutes façons):
extend
Déroulé avec python tutor lorsque l’on utilise extend
.
Avant l’exécution d’extend
, la situation est 100% identique à la précédente:
Par contre, la fonction extend
modifie le tableau pointé par t1
(et donc aussi par copie_t1
) en place, et ce sans modifier aucun pointeur. On aboutit donc à la situation suivante:
La variable copie_t1
a elle aussi été affectée par extend
, et ce n’est probablement pas l’effet recherché par le programmeur.
À retenir: Lorsque l’on modifie des variables en place (c’est-à-dire avec un effet de bord), cela peut potentiellement engendrer des erreurs dans le programme dès lors que des données sont partagées, ce qui est extrêmement courant.
On peut vouloir créer un tableau contenant par exemple 100 éléments, initialement tous à zéro. Il existe déjà un moyen de faire cela en l’état de nos connaissances: utiliser un tableau initialement vide, et lui rajouter 100 fois l’élément 0 à l’aide de append
t = []
for i in range(100):
t.append(0)
Le tableau t
contient alors les valeurs suivantes:
'[0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0]'
Il existe cependant une syntaxe spéciale en python qui permet de réaliser cela: l’opération *
appliqué entre un tableau et un nombre (dans cet ordre) va dupliquer le tableau autant de fois qu’indiqué par le nombre.
>>> t = [0] * 25
>>> repr(t)
'[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]'
Note: La fonction
repr
permet d’afficher une valeur telle que l’on aurait dû la taper pour la saisir en python (cela évite notamment que le tableau soit affiché sur 100 lignes dans la cellule. Essayez sans lerepr()
pour vous en rendre compte…)
À noter que ce mécanisme de duplication fonctionne quelle que soit la taille du tableau initial:
>>> t = [0, 1] * 25
>>> repr(t)
'[0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]'
On utilisera souvent cette syntaxe pour initialiser des tableaux dont on sait à l’avance (en début d’algorithme) quelle sera leur taille.