Outils pour utilisateurs

Outils du site


dev:python:core:tuples

Python: le type tuple

le tuple (traduit couple ou n-uplets) est un type builtin très proche de la liste mais immuable: c'est une séquence, on peut donc y appliquer les opérations telles que:

  • Accéder aux éléments avec l’opérateur d'indexation [] ;
  • Le test d'appartenance avec in ;
  • Faire du slicing etc

La différence fondamentale entre la liste et le tuple est que le tuple est un objet immuable: une fois l'objet créé en mémoire il ne sera pas modifié.

Il est important d'appréhender les spécificités et les comportements du tuple car il participe à certains mécanismes importants dans python (clés de dictionnaires et tuple unpacking notamment).

Un tuple est généralement défini par une paire de parenthèses contenant les éléments séparés par des virgules. Comme une liste, un tuple peut contenir des éléments de types différents.

>>> (1, 2, 3)
(1, 2, 3)
 
>>> ('a', 'b', 'c')
('a', 'b', 'c')
 
>>> (42, '!')
(42, '!')

On notera tout de même que les parenthèses sont facultatives, c’est la virgule qui définit réellement un tuple. Comme pour les opérations arithmétiques, les parenthèses servent en fait à gérer les priorités et mettre en valeur le tuple.

>>> 1, 2, 3
(1, 2, 3)
 
>>> 1, 2, 3 * 3
(1, 2, 9)
 
>>> (1, 2, 3) * 3
(1, 2, 3, 1, 2, 3, 1, 2, 3)

Attention à la syntaxe lors de la création d'un tuple contenant un seul élément. Il doit bien être obligatoirement suivi par la virgule afin que l’interpréteur ne considère pas les parenthèse comme un groupement d'opérations c'est à dire un changement de priorité mais bien comme la création d'un objet de type tuple:

>>> # Ces instructions NE créent PAS de tuple!
>>> t1 = (3)
>>> type(t1)                                                                                    
int
 
>>> t2 = ('4')
>>> type(t2) 
str
 
# Alors que celles-ci OUI
>>> t1 = (3,)
>>> type(t1)
tuple
 
>>> t2 = '4',
>>> type(t2)
tuple
Comme montré ci-dessus, pour un tuple singleton, c'est à dire un tuple d'un seul élément il ne faut pas oublier de placer la virgule.

Par ailleurs, il est possible de définir un tuple vide à l’aide d’une simple paire de parenthèses (il n’y a dans ce cas pas de confusion avec d’autres utilisations possibles des parenthèses).

>>> tp = ()
 
>>> type(tp)
<class 'tuple'>

Pour cette raison, pour lever toute ambiguïté et se conformer aux recommandations, il vaut mieux toujours terminer les lignes de définitions des tuples et listes par une virgule et répartir les éléments sur plusieurs lignes n’excédant pas 79 caractères.

Ci-dessous un exemple de définition conforme:

t1 = ( 1, 2, 3, 
       4, 5, 6, 
     )

Ordonnancement

Les tuples sont ordonnables les uns par rapport aux autres, de la même manière que les listes.

>>> (1, 2, 3) < (1, 2, 4)
True
 
>>> (1, 2, 3) <= (1, 2, 2)
False

Les fonctions len, min, max, all, any etc. sont aussi applicables aux tuples.

>>> len(values)
3
 
>>> min(values)
4
 
>>> max(values)
6
 
>>> all((True, True, False))
False
 
>>> any((True, True, False))
True

Conversion de types

On peut facilement passer d'un tuple à une liste grace à la fonction built-in list() qui renvoie une référence à une liste à partir d'un objet de type tuple:

>>> t2 = 'un', 2, 3.0, '4', 5
>>> type(t2)
tuple
 
>>> l2 = list(t2)
>>> l2
['un', 2, 3.0, '4', 5]

On peut par exemple opérer sur la liste puis créer à nouveau un tuple avec la fonction built-in tuple():

>>> l2[0] = 1
>>> t2 = tuple(l2)
 
>>> type(t2)
tuple
 
>>> t2
(1, 2, 3.0, '4', 5)

Le tuple étant immuable, on a bien créé une liste à partir du tuple, modifié la liste puis créer un nouvel objet tuple.

Cas d'usage du tuple

On peut parfois se demander quand utiliser un tuple et quand utiliser une liste. Le tuple étant comparable à une liste non modifiable, il peut donc être utilisé pour toutes les opérations attendant une liste et ne cherchant pas à la modifier. Il est même préférable de l’utiliser si l’on sait qu’il ne sera jamais question de modification, ou si l’on veut empêcher toute modification.

Mais il y a aussi des opérations qui ne sont possibles qu’avec les tuples. Étant non modifiables, ils peuvent être utilisés en tant que clés de dictionnaires.

>>> worldmap = {(0, 0): 'x', (0, 1): '.', (1, 0): '.', (1, 1): 'x'}
>>> worldmap[(1, 0)]
'.'
 
>>> worldmap[(1, 1)] = ' '
>>> worldmap
{(0, 0): 'x', (0, 1): '.', (1, 0): '.', (1, 1): ' '}
 
 
>>> # Les parenthèses sont encore une fois facultatives lors des accès.
>>> worldmap[0, 0]
'x'

Cette structure permet ainsi de représenter d’une grille de données où chaque case est associée à ses coordonnées.

Si un tuple contient une liste, rien n’empêche d’ajouter des éléments à cette liste.

>>> events = ('29/05/2019', ['anniversaire', 'soirée'])
>>> events[1].append('rdv coiffeur')
>>> events
('29/05/2019', ['anniversaire', 'soirée', 'rdv coiffeur'])

Un tel tuple ne pourra donc pas être utilisé comme clé de dictionnaire, parce qu’il contient une liste qui ne peut pas être utilisée comme tel.

>>> {events: None}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

Mais beaucoup d’utilisations des tuples sont tous simplement implicites. C’est en effet une manière de faire des assignations multiples de variables.

>>> a, b = 1, 2
>>> a
1
 
>>> b
2

Techniquement, cela revient à écrire (a, b) = (1, 2), ou encore :

>>> tmp = (1, 2)
>>> (a, b) = tmp

tuple unpacking

Le tuple unpacking est une opération largement utilisée en python. C'est une affectation entre les éléments d'un tuple et d'un objet quelconque de type séquence:

(a, b) = [12, 33]

Après exécution de l'instruction ci-dessus, la variable a référencera la valeur entière 12 et la variable b la valeur entière 33.

Comme les parenthèses sont facultatives on peut réécrire l'instruction précédente comme suit:

a, b = [12, 33]

Pour que l'unpacking puisse se faire, le nombre d’éléments dans le tuple doit correspondre au nombre d'éléments de la séquence. Le code ci-dessous lève une exception:

>>> a, b, c = ['un', 'deux', 'trois', 'quatre']                                                 
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-48-ed7192e8ea5b> in <module>
----> 1 a, b, c = ['un', 'deux', 'trois', 'quatre']
 
ValueError: too many values to unpack (expected 3)

Le tuple unpacking rend le code produit plus concis et le rapproche du langage naturel que la manipulation d'indices facilitant ainsi la maintenance. C'est ce mécanisme qui est aussi à l’œuvre dans l'expression ci-dessous:

>>> l1 = [ 1, 2, 3.0,
        'quatre', True, 
      ]
 
>>> for index,value in enumerate(l1): 
        print(f"{index:2d} = {value}")

Dans l'exemple ci-dessus, à chaque tour de boucle, la fonction enumerate() retourne une séquence de 2 éléments affectés aux variables index et values grâce au mécanisme de tuple unpacking.

L'unpacking fonctionne également avec les listes:

liste = [1, 2, 3]
[gauche, milieu, droit] = liste
print('élément gauche', gauche, 'élément central', milieu, ' élément droit', droit)

Pour que l'unpacking fonctionne il faut:

  • Que le terme à droite du signe '=' soit un itérable,
  • Que le terme à gauche du signe '=' soit un tuple ou une liste
  • les deux termes aient la même longueur ou utilisent la notation *arg voir section extend unpacking.

Une propriété amusante de l'unpacking de tuples est qu’elle permet facilement d’échanger les valeurs de deux variables. En effet, il suffit de construire un tuple avec les valeurs des deux variables puis de le déconstruire vers ces deux mêmes variables en les inversant.

>>> a = 3
>>> b = 5
 
>>> a, b = b, a
 
>>> a
5
 
>>> b
3

Extended tuple unpacking

C'est un manière simple d' isoler des éléments dans une séquence:

>>> l1 = list(range(10))
 
>>> x, *y = l1
 
>>> x
0
 
>>> y
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Addition de tuples

Le tuple est immuable mais il est tout a fait possible de faire des opérations comme l'addition sur des tuples. L'opération aboutit sur la création d'un nouveau tuple:

>>> t1 = (1,2,3)
 
>>> id(t1)
140325857254400
 
>>> t1 += (4, 5, 6)
 
>>> t1
 (1, 2, 3, 4, 5, 6)
 
>>> id(t1)
140325853457664

On voit bien ici que la variable t1 ne référence plus le même objet en mémoire après l'opération d'addition.

Références

dev/python/core/tuples.txt · Dernière modification : 2023/12/02 18:35 de yoann