Les tuples
sont le premier conteneur que l’on va voir en python. Ils permettent ainsi une référence direct à plusieurs objets simultanément. Syntaxiquement, il s’agit d’une suite d’objets python séparés par des virgules et entourés par des parenthèses:
>>> (1, 2, 3)
(1, 2, 3)
On peut bien sûr associer une variable à un tuple
:
>>> x = (1, 2, 3)
>>> x
(1, 2, 3)
PIEGE pour créer un tuple
avec un seul élément il faudra quant même mettre une virgule:
>>> x = (1)
>>> x
1
>>> type(x)
<class 'int'>
>>> y = (1,)
>>> y
(1,)
>>> type(y)
<class 'tuple'>
Le premier constat à faire est qu’un tuple est une collection ordonnée d’objets python. On va accéder aux éléments séparément en utilisant leur positionnement.
ATTENTION cependant, on va plutôt parler d’indice que de position. En effet, suivant la convention héritée de précédents langages, on commence à 0
. De la même façon que 0
est le premier nombre entier.
On pourra consulter ceci pour un argumentaire (par un des pères fondateurs de l’informatique: Edsger Dijkstra) justifiant le fait de commencer à 0
l’indiçage. Il justifie aussi le fait que, comme on le verra plus tard, le slicing ne contient pas le dernier indice.
La syntaxe formelle est alors le nom du tuple suivi de [
de l’indice et de ]
:
>>> y = (10, 15, -5)
>>> y
(10, 15, -5)
>>> y[0]
10
>>> y[1]
15
>>> y[2]
-5
Suivant cet exemple 10
est l’élément d’indice 0
, 15
est d’indice 1
et -5
d’indice 2
.
Les éléments d’un tuple
peuvent tout à fait être de natures différentes:
>>> u = (1,)
>>> u
(1,)
>>> v = (2, u)
>>> v
(2, (1,))
>>> w = (3, u, v)
>>> w
(3, (1,), (2, (1,)))
>>> x = (4, u, v, w)
>>> x
(4, (1,), (2, (1,)), (3, (1,), (2, (1,))))
>>> type(x)
<class 'tuple'>
>>> type(x[0])
<class 'int'>
>>> type(x[1])
<class 'tuple'>
Une fois formé un tuple
ne pourra plus évoluer: on ne peut pas changer des éléments interne, on ne peut pas non plus en rajouter ni en enlever:
>>> x = (1, 2, 3)
>>> x[1] = 4
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
La structure de conteneur dynamique sera vue plus tard, il s’agit des list
. Elles sont bien sûr beaucoup plus versatile, mais c’est souvent pour bénéficier des contraintes des tuples
qu’on choisit ces derniers. Cela garantit des invariants qui rendent la compréhension d’un programme plus simple.
ATTENTION en fait il y a un cas de figure (qu’on cherchera surtout à éviter) où un tuple
pourra changer. C’est lorsqu’un de ses éléments mute. On reviendra plus tard là dessus quand on parlera de mutation.
Il s’avère en fait que les accès aux éléments d’un tuple
par leurs indices sont moins utilisés que ce à quoi on pourrait s’attendre. La méthode alternative est de déstructurer ce tuple
en affectant séparément le contenu:
>>> annees = (476, 1453, 1789)
>>> annees
(476, 1453, 1789)
>>> (fin_empire_romain, chute_constantinople, revolution_francaise) = annees
>>> fin_empire_romain
476
>>> chute_constantinople
1453
>>> revolution_francaise
1789
>>> annees
(476, 1453, 1789)
ATTENTION constater bien que le fait de déstructurer le tuple
ne l’a pas fait disparaître pour autant.
Noter que la coutume en python est en fait d’omettre les parenthèses lors de la déstructuration. On écrirait donc plutôt:
>>> fin_empire_romain, chute_constantinople, revolution_francaise = annees
On utilise en fait souvent cette façon de faire pour affecter simultanément plusieurs variables:
>>> x, y, z = 1, 2, 3
>>> x
1
>>> y
2
>>> z
3
Le tuple
est alors implicite
Mentionnons maintenant une convention python importante. Lorsque seul une partie du tuple
nous importe, le nom de variable choisie pour les parties inutiles est alors toujours _
. C’est une façon de signaler au lecteur du code qu’il n’est pas la peine de s’intéresser à cette partie pour la suite:
>>> annees = (476, 987, 1453, 1789)
>>> _, sacre_hugues_capet, _, revolution_francaise = annees
>>> duree_dynastie_capetienne = revolution_francaise - sacre_hugues_capet
>>> duree_dynastie_capetienne
802
Finissons maintenant par mentionner une syntaxe de déstructuration avancée. Par exemple si on veut récupérer le premier et dernier éléments d’un tuple
de taille 3 on ferait:
>>> triplet = (1, 2, 3)
>>> premier, _, dernier = triplet
>>> premier
1
>>> dernier
3
Mais si le tuple
était de longueur 4, il faudrait insérer un autre _
, et ainsi de suite. Et si on ne connait pas la taille du tuple on ne peut carrément pas utiliser cette syntaxe:
>>> mon_tuple = (1, 2, 3, 4, 5)
>>> premier, milieu, dernier = mon_tuple
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 3)
En fait l’opérateur *
permet de signaler qu’une des variables est un conteneur est absorbe le trop plein:
>>> mon_tuple = (1, 2, 3, 4, 5)
>>> premier, milieu, dernier = mon_tuple
>>> premier, *milieu, dernier = mon_tuple
>>> premier
1
>>> dernier
5
>>> milieu
[2, 3, 4]
ATTENTION les crochets []
en lieu des parenthèses ()
indique que le conteneur obtenu est une list
et pas un tuple
.
REMARQUE la déstructuration s’applique en fait à de nombreux autres conteneurs que les seuls tuples
. C’est une syntaxe extrêmement utilisée en python courant et donc à maitriser.
len
sur différents tuples
que semble-t-elle faire?On pourra essayer
>>> help("TUPLES")
pour voir la documentation sur la structure de donnée. Attention on a aussi des informations sur les listes (list
) et les range
qui forment à trois les sequence
de python.
On regardera
>>> help("TUPLELITERALS")
pour voir la grammaire de création de tuple.
On pourra regarder de nouveau
>>> help("ASSIGNMENT")
pour voir toutes les possibilités de déstructuration. (En particulier la partie décrivant target_list
)
>>> restant0 = 1
>>> (decimale1, restant1) = divmod(10 * restant0, 21)
>>> (decimale2, restant2) = divmod(10 * restant1, 21)
>>> (decimale3, restant3) = divmod(10 * restant2, 21)
>>> (decimale4, restant4) = divmod(10 * restant3, 21)
>>> decimale1, decimale2, decimale3, decimale4
(0, 4, 7, 6)
C’est une astuce très classique en python dont on pourra régulièrement tirer profit.
>>> a, b = 10, 25
>>> a
10
>>> b
25
>>> a, b = b, a
>>> a
25
>>> b
10
len
est l’abréviation de length. La fonction renvoie le nombre d’éléments du tuple
, comme on le voit ci-dessous. Là encore elle accepte tout type de conteneur.
>>> u = (1,)
>>> len(u)
1
>>> x = (1, 2)
>>> len(x)
2
>>> y = (1, 2, 3)
>>> len(y)
3