Une page de Le Lab de la taverne

Découvrez les tuples en Python

Par Darko Stankovski, 20/04/2023 (Mise à jour 17/04/2026) — Débutant

Si je vous propose une série d’articles sur les structures de données en Python, il faudrait vous parler des tuples ou n-uplets en bon français.

Les n-uplets sont un type de base, on les apprends à peu près en même temps que les listes. Un débutant en crée rarement mais qu’on le veuille ou non, on en récupère souvent. Retourner plusieurs données par une fonction par exemple retourne un n-uplet.

En tant que débutant, on accepte les n-uplets mais on comprends rarement à quoi sert ce type et pourquoi un n-uplet plutôt qu’une liste ?

Dans cet article, je vais aborder l’essentiel sur ces n-uplets.

Tuple ou n-uplet ?

Avant de commencer, une précision des termes. Tuple et uplet signifient la même chose, en mathématiques, il s’agit d’une collection ordonnée finie d’objets et la notion de n-uplet signifie qu’il contient n éléments. La différence est que tuple est le terme anglais et n-uplet le français.

La documentation Python en français fait l’effort de traduction. Cependant, dans le langage courant, on a tendance à garder le mot anglais car la majorité des informations sont en anglais.

Je fais l’effort à l’écrit français d’utiliser le terme français mais pour un post de blog, il faut aussi penser indexation… C’est la raison pour laquelle je placerai aussi le mot anglais.

Créer un tuple

Nous avons tous découvert les tuples comme une collection encadrée de parenthèses. Dans le code suivant, en ligne 1 je crée une liste, en 2, un n-uplet.

my_quizz = ["Meaning of life", 42]
my_quizz = ("Meaning of life", 42)

Cependant, le symbole pour créé un tuple est la virgule et uniquement la virgule. Les parenthèses ne sont qu'un symbole de priorité. Les deux lignes suivantes sont strictement équivalentes et créent toutes deux un tuple.

my_quizz = ("Meaning of life", 42)
my_quizz = "Meaning of life", 42

Comprendre cela est indispensable pour créer un tuple ne contenant qu'un seul élément. En ligne 1, l'entier encadré de parenthèses reste un entier. En ligne 2, l'entier suivi d'une virgule représente un tuple d'une données. Et si ça pique… Vous pouvez encadrer cette expression de parenthèses comme à la ligne 3.

my_value = (42)   # my_value contient un entier
my_value = 42,    # my_value contient un tuple
my_value = (42,)  # my_value contient un tuple

Et plus généralement, les déclarations de n-uplets précédentes peuvent s’écrire :

my_value = 42,
my_quizz = "Meaning of life", 42
my_quizz = "Meaning of life", 42,

Les lignes 2 et 3 sont exactement les mêmes. Je vous ai juste indiqué les deux syntaxes possibles.

Alors je sais, ça pique un peu de voir une virgule en fin de ligne. On a une impression de truc pas fini. Mais c’est un code valide.

Sachant cela, vous devez vous rendre compte que vous avez certainement créé des tuples sans le savoir comme avec les fonctions qui retourneraient plusieurs valeurs :

def ma_func():
    return "meaning of life", 42

Vous comprenez maintenant qu'après le return, vous créez vous-même un tuple.

Un type immuable

Les tutos de base sur le n-uplets enseignent que le n-uplet est un type immuable. Immuable signifie que vous ne pouvez pas le modifier. Ainsi, pour un n-uplet

  • Vous ne pouvez pas ajouter une donnée
  • Vous ne pouvez pas supprimer une donnée
  • Vous ne pouvez pas remplacer une donnée

Attention pour ce dernier point : ne pas remplacer la donnée signifie que vous ne pouvez pas affecter une nouvelle donnée à un indice de n-uplet existant. Vous pouvez modifier l’état d’une données mutable dans un n-uplet (ajouter un élément à une liste contenue dans le n-uplet par exemple).

Un type performant

La conséquence de l’immuabilité des n-uplets font qu’ils sont rapides. Sous ipython, j’ai fait un %timeit et ai obtenu le résultat suivant pour la création d’une liste et d’un n-uplet :

>>> %timeit [45, 25, 2, 12, 0]
26.8 ns ± 0.146 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
>>> %timeit (45, 25, 2, 12, 0)
4.13 ns ± 0.0263 ns per loop (mean ± std. dev. of 7 runs, 100,000,000 loops each)

27 ns contre 4 ns… Pour la création de ce type de 5 valeurs, il faut donc presque 7 fois plus de temps pour créer une liste par rapport à un n-uplet.

Bien évidemment, le gain est infime pour une donnée mais j’ai repris ici le cas des données de l’explosion de l’article des explosions dans les jeux vidéos. Une explosion, c’est 100 particules donc 100 collections de ce type. Et vous pouvez évidemment avoir plusieurs explosions (donc plusieurs centaines de collections). Avec le besoin de rapidité pour générer une image afin d’avoir un bon frame rate, le n-uplet est le type évident à utiliser.

On peut faire la même chose pour la consultation. Essayons l’unpacking (le déballage) :

>>> %timeit x, y, vx, vy, age = [45, 25, 2, 12, 0]
32.4 ns ± 0.135 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
>>> %timeit x, y, vx, vy, age = 45, 25, 2, 12, 0
16.3 ns ± 0.0518 ns per loop (mean ± std. dev. of 7 runs, 100,000,000 loops each)

La différence n’est pas aussi spectaculaire que la création mais elle est toujours significative.

L’explication de la performance des n-uplets tient dans leur implémentation. Les listes stockent les données dans deux blocs de mémoire, un à taille fixe et l’autre variable pour la donnée. Les n-uplets dans un seul.

Cas d’usage des tuples

La question qu’on tous les débutants en Python (et… Pas que les débutants) est quand utiliser les n-uplets ? Si on reprends la partie précédente, ce devrait être quand on a besoin de performance pour construire et/ou parcourir une collection immuable. Et ce cas coule de source.

N-uplets et listes sont en Python des séquences d’objets. Ceci veut dire que vous pouvez stocker des types différents dans ces séquences. Mais dans la pratique, l’usage des listes sera plutôt de stocker des types de données uniformes et celui des n-uplets des types potentiellement hétérogènes. Le n-uplet représentera en lui-même une donnée complexe. Une fiche de quizz par exemple est représentée par une question et une réponse, dans mon exemple ci-dessus, le n-uplet est le plus adapté.

Et c’est ce qui se passe dans la pratique. Si vous prenez le code à propos des explosions, les particules sont représentées sous forme d’un n-uplet mais sont stockées dans une liste. Ok, l’exemple n’est pas très bien choisi car le n-uplet ne contient que des réels mais la logique est bien là : la particule est une information (composée de plusieurs informations) et l’exposition est une liste d’informations.

Notez que globalement, les fonctions qui retournent des données « complexes » retourneront des n-uplet. C’est le cas des méthodes d’accès aux données de l’API des bases de données par exemple.

En conclusion

Les n-uplets ou tuples sont donc des séquences plus performantes que les listes. Elles sont destinée à contenir des éléments de types différent qui composent par leur ensemble une information. C’est donc un type adapté à la manipulation d’une quantité importante d’information qui ne nécessite pas de modification.

Cependant, si vous devez accéder plusieurs fois aux champs de la séquence, l’écriture par indice peut-être pénible. On peut alors songer aux namedtuple présentés dans l’article précédent. Mais qu’en est-il de la performance ? Ce sera le sujet d’un article dédié.

Licence Creative Commons

Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Pas de Modification 4.0 International