Les tuples en Python

En plus des listes, Python propose un autre type de structure de données : les tuples.

Un tuple ne peut pas être modifié après l'assignation car c'est un objet immuable.

C'est la principale différence entre les tuples et les listes.

Comment créer un tuple ?

Pour créer un tuple en Python, on utilise les parenthèses () puis on place les éléments à l'intérieur en les séparant par une virgule.

Comme les listes, les tuples peuvent contenir un nombre illimité d'éléments qui peuvent être de différents types.

Vous pouvez aussi stocker un tuple à l'intérieur d'un tuple :

t = ()  # Un tuple python vide
print(t) # ()

t = ('spam', 'eggs') # Un tuple python contenant deux chaînes de caractères
print(t)  # ('spam', 'eggs')

t = ('spam', 'eggs', 9, ['one', 'two', 'three'], True) # Un tuple python avec des éléments de différents types
print(t)  # ('spam', 'eggs', 9, ['one', 'two', 'three'], True)

t = ('spam', 'eggs', (1, 2, 3), 9.4, True) # Un tuple python contenant un autre tuple
print(t)  # ('spam', 'eggs', (1, 2, 3), 9.4, True)

Sachez que les parenthèses sont optionnelles ! Je vous conseille tout de même de les utiliser pour respecter la convention et parce que c'est aussi une bonne pratique 🙂

t = ('spam', 'eggs')
t2 = 'spam', 'eggs'

print(t)         # ('spam', 'eggs')
print(t2)        # ('spam', 'eggs')

Créer un tuple avec un seul élément

Pour créer un tuple avec un seul élément, il faut ajouter une virgule après cet élément, même si les parenthèses sont facultatives.

Cette virgule indique à Python qu'il s'agit d'un tuple et non d'une simple expression avec des parenthèses.

mon_tuple = (1,)

Vous pouvez également créer un tuple avec un seul élément sans utiliser de parenthèses, en écrivant simplement une virgule après l'élément :

mon_tuple = 1,

Pourquoi la virgule est-elle nécessaire ?

La virgule est nécessaire pour différencier un tuple d'une simple expression entourée de parenthèses. Sans la virgule, Python interpréterait l'expression comme une simple valeur entourée de parenthèses et non comme un tuple. Voici un exemple pour illustrer ce point :

# Ceci n'est pas un tuple
pas_un_tuple = (1)
print(type(pas_un_tuple))  # Résultat : <class 'int'>

# Ceci est un tuple avec un seul élément
mon_tuple = (1,)
print(type(mon_tuple))  # Résultat : <class 'tuple'>

Dans cet exemple, pas_un_tuple est simplement une expression entourée de parenthèses et est interprétée comme un entier. En revanche, mon_tuple est un tuple avec un seul élément grâce à la virgule ajoutée après l'élément.

Quelle est la différence entre un tuple et une liste ?

Contrairement aux listes, les tuples ne permettent pas d'ajouter, de supprimer ou de modifier des éléments une fois créés. Toute tentative de modification d'un tuple entraînera une erreur.

La différence fondamentale entre les listes et les tuples est donc leur mutabilité.

Les listes sont modifiables, ce qui signifie que vous pouvez ajouter, supprimer ou modifier des éléments après la création de la liste. Les tuples, en revanche, sont immuables. Une fois créés, vous ne pouvez pas modifier leurs éléments.

Les avantages des tuples par rapport aux listes

  • Immuabilité : Les tuples sont immuables, ce qui signifie que leurs éléments ne peuvent pas être modifiés une fois qu'ils ont été créés. Cette caractéristique garantit que les données stockées dans un tuple restent constantes, ce qui peut être utile dans certaines situations où la cohérence des données est cruciale.
  • Sécurité des données : En raison de leur immuabilité, les tuples peuvent protéger les données contre les modifications accidentelles ou indésirables. Par exemple, si vous passez un tuple en argument à une fonction, vous pouvez être sûr que la fonction ne modifiera pas les éléments du tuple, contrairement à une liste qui pourrait être modifiée.
  • Performance : Les tuples sont généralement plus rapides et consomment moins de mémoire que les listes, car ils sont immuables. Si vous n'avez pas besoin de modifier les éléments d'une collection, il est préférable d'utiliser un tuple pour des raisons de performance.
  • Utilisation : Comme les tuples sont immuables, ils peuvent être utilisés comme clé dans un dictionnaire ce qui n'est pas le cas des listes.
  • Lisibilité du code : L'utilisation de tuples peut améliorer la lisibilité et la compréhension du code en indiquant clairement qu'une collection d'éléments n'est pas censée être modifiée. Cela peut aider à prévenir les erreurs et à faciliter la maintenance du code.

J'insiste particulièrement sur ce dernier point. Le type des variables que vous créez a une grande importance.

Par exemple, si je souhaite stocker en mémoire les valeurs RGB d'une couleur, je peux très bien utiliser une liste ainsi :

rouge = [255, 0, 0]

Cependant, en utilisant une liste, je laisse penser à d'autres développeurs qui pourraient lire mon code que cette couleur peut être modifiée, par exemple pour rajouter une quatrième valeur indiquant la couche alpha :

>>> rouge = [255, 0, 0]
>>> rouge.append(128)  # Rouge semi-transparent
>>> print(rouge)
[255, 0, 0, 128]

En utilisant un tuple, j'indique clairement mon intention de définir une variable qui ne peut pas être modifiée, et que ma couleur ne contiendra donc que des données de RGB et pas de données pour la couche alpha :

>>> rouge = (255, 0, 0)  # Pas touche ! 

Créer un tuple vide

Pour créer un tuple vide en Python, vous pouvez simplement utiliser une paire de parenthèses vides, comme ceci :

mon_tuple = ()

ou en utilisant la fonction tuple sans argument :

mon_tuple = tuple()

Un tuple vide peut être utile lorsque vous souhaitez initialiser une variable à un tuple, mais que vous ne disposez pas encore des éléments à ajouter. Il est à noter cependant que cette façon de faire est rarement utilisée car quelque peu contraire à la logique immuable des tuples.

Par exemple, si vous avez un programme qui utilise un tuple pour stocker des données, mais que vous ne savez pas encore quelles données vous allez stocker, vous pouvez initialiser le tuple avec une valeur vide, puis ajouter des éléments au tuple au fur et à mesure de leur disponibilité :

mon_tuple = ()
mon_tuple += (128,)
print(mon_tuple)

Bien qu'un tuple soit immuable en Python, il est possible de créer un tuple vide et de le modifier en ajoutant des éléments ultérieurement, grâce à la concaténation de tuples.

Accéder à un élément

Comme pour les listes, il y a plusieurs façons d'accéder à un ou plusieurs éléments contenus dans un tuple.

Avec son indice

On peut utiliser les crochets [] pour accéder à un élément via son indice.

Comme pour toutes les structures de données en Python, le premier indice est 0.

Si vous avez un tuple qui contient trois éléments, l'indice du premier élément sera 0, celui du deuxième 1 et celui du troisième 2:

t = ('spam', 'eggs')
print(t[0])  # 'spam'
print(t[1])  # 'eggs'

Même si les tuples se définissent avec des parenthèses (), il faut toujours utiliser les crochets[] pour accéder à un item grâce à son indice.

Si vous tentez d'utiliser un indice dont la valeur est supérieure à la longueur du tuple, vous déclencherez une erreur de type IndexError :

t = ('spam', 'eggs')
print(t[2])  # IndexError: tuple index out of range

L'indice que vous utilisez doit obligatoirement être un int sans quoi vous aurez le droit à une erreur de type TypeError:

t = ('spam', 'eggs')
print(t[1.0])  # TypeError: tuple indices must be integers or slices, not float

Avec un indice négatif

Vous pouvez aussi accéder à l'élément d'un tuple en utilisant un indice négatif !

C'est pratique lorsque vous avez un tuple qui contient beaucoup de valeurs et que vous avez besoin d'accéder aux dernières :

t = ('s', 'p', 'a', 'm')
print(t[-1])  # 'm'
print(t[-3])  # 'p'

Encore une fois, comme pour les listes, vous pouvez utiliser le slicing pour préciser un intervalle de recherche.

Pour rappel, la syntaxe pour le slicing est : [début:fin:pas]

t = ('d', 'o', 'c', 's', 't', 'r', 'i', 'n', 'g')

# Tous les items jusqu'à l'index 3
print(t[:3])    # ('d', 'o' 'c')

# Tous les items à partir de l'index 3 
print(t[3:])    # ('s', 't', 'r', 'i', 'n', 'g'

# Tous les items compris enter l'index 2 et l'index 6
print(t[2:6])   # ('c', 's', 't', 'r')

# Un item sur deux à partir de l'index 1 et jusqu'à la fin du tuple 
print(t[1::2])  # ('o', 's', 'r', 'n')

# Copie du tuple
print(t[:])     # ('d', 'o', 'c', 's', 't', 'r', 'i', 'n', 'g')

La valeur de début de l'intervalle est inclusive alors quelle celle de fin est exclusive !

Packing & Unpacking

Lorsque vous créez des tuples, en réalité vous assignez un jeu de données à une variable.

De ce fait, vous pouvez aussi « déballer » (unpacker en anglais) ces données, c’est-à-dire déconstruire ce paquet pour récupérer chaque valeur contenue dans le tuple :

t = ('spam', 'eggs')
v1, v2 = t

print(v1)  # 'spam'
print(v2)  # 'eggs'

Quand vous faites ça, vous devez faire attention à ce qu'il y ait exactement le même nombre d'éléments d'un côté et de l'autre de l'assignation :

t = ('spam', 'eggs', 'knights')
v1, v2 = t          # ValueError: too many values to unpack (expected 2)
v1, v2, v3, v4 = t  # ValueError: not enough values to unpack (expected 4, got 3)

Cela fonctionne de la même façon avec ou sans les parenthèses !

C'est grâce à cette spécificité qu'on peut par exemple échanger les valeurs de deux variables sans passer par une variable temporaire :

a = 'spam'
b = 'eggs'

a, b = b, a

print(a) # 'eggs'
print(b) # 'spam'

Vérifier la présence d'une donnée dans un tuple

Pour vérifier la présence ou l'absence d'une donnée dans un tuple, vous pouvez utiliser l'opérateur in. L'opérateur in permet de déterminer si un élément spécifique est présent dans une séquence, comme un tuple, une liste ou une chaîne de caractères. Voici comment utiliser l'opérateur in pour vérifier la présence d'un élément dans un tuple :

mon_tuple = (1, 2, 3, 4, 5)

# Vérifier si l'élément 3 est présent dans le tuple
if 3 in mon_tuple:
    print("L'élément 3 est présent dans le tuple.")
else:
    print("L'élément 3 est absent du tuple.")

# Vérifier si l'élément 6 est absent du tuple
if 6 not in mon_tuple:
    print("L'élément 6 est absent du tuple.")
else:
    print("L'élément 6 est présent dans le tuple.")

L'opérateur in s'arrête au premier niveau du tuple. Si votre tuple contient des données imbriquées, les éléments à partir du second niveau ne seront pas détectés.

mon_tuple = (1, 2, [3, 4])
print(3 in mon_tuple)  # False

Modifier un tuple

Vous le savez, les tuples sont des objets immuables.

Cependant, vous pouvez quand même modifier les objets muables stockés à l'intérieur d'un tuple comme les listes, les dictionnaires, etc.

t = ('spam', 'eggs', [1, 2, 3], 'knights')
t[0] = 'lumberjack'  # TypeError: 'tuple' object does not support item assignment
t[2][0] = 9          # ('spam', 'eggs', [9, 2, 3], 'knights')

Vous pouvez également concaténer deux tuples à l'aide de l'opérateur plus + :

t1 = ('spam', 'eggs')
t2 = ('knights', 'lumberjack')

print(t1 + t2)  # ('spam', 'eggs', 'knights', 'lumberjack')

Supprimer un tuple

Vous ne pouvez pas supprimer un élément en particulier d'un tuple car les tuples sont des objets immuables.

Par contre, vous pouvez supprimer le tuple en entier grâce à l'instruction del :

t = ('spam', 'eggs', 'knights', 'lumberjack')

del t[0]  # TypeError: 'tuple' object doesn't support item deletion
del t
print(t)  # NameError: name 't' is not defined

Convertir les tuples Python en liste

Pour convertir un tuple en liste, nous pouvons utiliser la fonction intégrée list().

Cette fonction prend un tuple en argument et renvoie une nouvelle liste contenant les mêmes éléments que le tuple.

mon_tuple = (1, 2, 3, 4)
ma_liste = list(mon_tuple)
print(ma_liste)  # Résultat : [1, 2, 3, 4]

Dans cet exemple, nous avons converti mon_tuple en liste en utilisant la fonction list.

La variable ma_liste contient maintenant une liste avec les mêmes éléments que mon_tuple.

Conversion de listes imbriquées de tuples

Si vous travaillez avec des tuples imbriqués dans une liste, vous pouvez utiliser une compréhension de liste pour les convertir en listes.

liste_de_tuples = [(1, 2), (3, 4), (5, 6)]
liste_de_listes = [list(t) for t in liste_de_tuples]
print(liste_de_listes)  # Résultat : [[1, 2], [3, 4], [5, 6]]

Dans cet exemple, nous avons utilisé une compréhension de liste pour parcourir chaque tuple de liste_de_tuples et les convertir en listes à l'aide de la fonction list.

Pourquoi convertir des tuples en listes ?

Il peut être utile de convertir des tuples en listes lorsque vous avez besoin de modifier les éléments d'une collection.

Les listes sont modifiables, vous pouvez donc ajouter, supprimer ou modifier des éléments après avoir converti un tuple en liste. Par exemple :

mon_tuple = (1, 2, 3, 4)
ma_liste = list(mon_tuple)

# Ajouter un élément à la liste
ma_liste.append(5)
print(ma_liste)  # Résultat : [1, 2, 3, 4, 5]

# Modifier un élément de la liste
ma_liste[0] = 0
print(ma_liste)  # Résultat : [0, 2, 3, 4, 5]

Déterminer la longueur d'un tuple

Comme pour tous types de collection, on peut utiliser la fonction len pour déterminer le nombre d'éléments présents dans un tuple.

La fonction len ne compte que les éléments de premier niveau. Si vous avez 3 éléments dans votre tuple dont un des éléments est une liste de 2 items, la fonction len retournera 3 et non pas 5.

mon_tuple = (1, 2, 3)
print(len(mon_tuple))  # 3

mon_tuple = (1, 2, [3, 4])
print(len(mon_tuple))  # 3

Les méthodes disponibles avec les tuples

Étant des objets immuables, les méthodes sur les tuples sont peu nombreuses : il n'y en a que deux !

Récupérer le nombre d'occurrences dans un tuple avec count():

t = ('spam', 'eggs', 'knights', 'lumberjack')
print(t.count('knights'))  # 1

t = ('a', 'b', 'b', 'c', 'b', 'a', 'c', 'b')
print(t.count('b'))        # 4

Récupérer l'indice d'une valeur dans un tuple avec index():

t = ('spam', 'eggs', 'knights', 'lumberjack')
print(t.index('spam'))     # 0
print(t.index('knights'))  # 2