Tuple
Un tuple est une séquence non modifiable d'éléments. Tout comme les listes, un tuple peut être homogène ou hétérogène. Pour en déclarer un, il suffit de séparer ses éléments avec des virgules. Si on veut créer un tuple avec un seul élément, il suffit de placer une virgule derrière l'élément. Enfin, si on souhaite, on peut entourer les éléments du tuple de parenthèses. Voici plusieurs déclarations de tuples :
On peut choisir de délimiter ou non les valeurs d'un tuple par des parenthèses. Il y a néanmoins des situations où celles-ci sont obligatoires, à savoir lorsqu'on veut un tuple vide ou lorsqu'il y a une possible ambiguité. Définissons par exemple une fonction sum
qui fait la somme des éléments d'un tuple d'entiers :
Comme vous pouvez le constater, tout ce qu'on a vu à propos des listes s'applique également aux tuples, à l'exception des opérations de modification, évidemment. Supposons que l'on souhaite appeler la fonction sum
avec le tuple (1, 2, 3)
, on pourrait écrire :
On se retrouve malheureusement avec l'erreur d'exécution suivante :
Traceback (most recent call last): File "program.py", line 9, in <module> r = sum(1, 2, 3) TypeError: sum() takes 1 positional argument but 3 were given
Ce qui s'est passé est que l'interpréteur Python pense qu'on tente d'appeler la fonction en lui fournissant trois paramètres, alors qu'elle n'en accepte qu'un seul. L'appel correct s'écrit donc :
Une autre solution, qui ne forcerait pas l'utilisation des parenthèses consiste à passer par une variable intermédiaire :
Construire un tuple à partir de plusieurs valeurs, comme on l'a fait dans la première instruction, est une opération appelée emballage. On combine des valeurs pour former un tuple, référencé par une seule variable grâce à laquelle on pourra accéder aux valeurs combinées à l'aide de leur indice dans le tuple.
Fonction qui renvoie plusieurs valeurs
L'un des intérêts du tuple est qu'il permet de définir des fonctions qui renvoient plusieurs valeurs. Il suffit en fait de renvoyer un tuple. Définissons une fonction qui cherche si un élément donné se trouve ou non dans une liste. Si c'est le cas, elle renvoie True
ainsi que le plus petit indice où se trouve l'élément. Sinon, elle renvoie False
et la valeur spéciale None
comme indice, indiquant une absence de valeur :
Les deux instructions return
procèdent à un emballage d'une valeur booléenne et d'un nombre entier (ou None
) pour former un tuple qui est renvoyé. Prenons par exemple les deux appels suivants :
L'exécution de ces instructions produit le résultat suivant indiquant que l'élément $2$ a été trouvé dans la liste à l'indice $1$, et que l'élément $6$ n'a pas été trouvé dans la liste :
(True, 1) (False, None)
Vous pourriez vous demander, légitimement, pourquoi on ne s'est pas contenté de renvoyer False
dans le cas où l'élément recherché n'est pas dans la liste. On aurait pu, mais ce n'est pas une bonne pratique de renvoyer différents types de valeurs ; c'est même parfois impossible.
Dans l'exemple précédent, tout ce qu'on fait avec la valeur de retour, c'est l'afficher avec la fonction print
. Cela ne pose donc aucun problème d'avoir deux types de données différents en valeur de retour. De même, on pourrait stocker la valeur de retour de la fonction dans une variable sans que cela ne pose de soucis :
On a précédemment vu qu'on pouvait construire un tuple à partir d'éléments simples en faisant un emballage. Il est également possible de faire l'opération inverse, appelée déballage, c'est-à-dire affecter chaque élément d'un tuple à une variable différente :
Dans ce cas, il n'est plus possible pour la fonction find
de renvoyer tantôt un tuple à deux élément, tantôt un seul booléen, sans quoi une erreur d'exécution se produira dans certains cas.
Opérateur de déballage
On vient de voir qu'on pouvait déballer un tuple lors d'une affectation, en ayant à gauche de l'opérateur d'affectation un tuple de variables avec autant d'éléments qu'il y en a dans le tuple à sa droite :
On peut également déballer un tuple dans les paramètres d'une fonction lors d'un appel, avec l'opérateur de déballage (*
). Voici une fonction qui renvoie la plus grande valeur entre trois entiers donnés :
Si on a un tuple contenant trois nombres entiers et qu'on souhaite appeler cette fonction avec les trois nombres du tuple, il faut utiliser l'opérateur de déballage et donc écrire :
Affectation multiple
Les propriétés d'emballage et de déballage des tuples permettent de modifier la valeur de plusieurs variables en même temps, avec des valeurs différentes. C'est ce qu'on appelle une affectation multiple. On peut par exemple écrire :
L'affectation des trois variables se déroule en même temps. Cette caractéristique permet d'échange les valeurs de deux variables très facilement, grâce à l'instruction suivante :
Tuple nommé
Pour accéder à un élément d'un tuple, il faut utiliser son indice. Dans le cas de tuples hétérogènes, ce n'est pas toujours très intuitif. Reprenons l'exemple précédent d'un tuple qui représente un article d'un magasin :
Pour accéder au code-barres, il faut écrire item[0]
, pour accéder à la description de l'article, on utilise item[1]
et enfin item[2]
permet d'avoir le prix de l'article.
Pour rendre plus explicite qu'on a un tuple hétérogène dont chaque élément représente un attribut différent, on peut utiliser un tuple nommé. Pour cela, il faut avant tout déclarer un nouveau type de tuple nommé, avec namedtuple
, en déclarant un nom et une liste d'attributs. Voici comment déclarer un tuple nommé Item
composé d'un code-barres, d'une description et d'un prix :
Une fois le nouveau type de tuple nommé créé, on peut créer des tuples nommés comme suit :
La variable coca
contient un tuple nommé qui est illustré à la figure 6. Toutes les opérations précédemment vues sur les tuples sont également applicables sur les tuples nommés. On peut, par exemple, écrire les instructions suivantes :
L'exécution de ces instructions affiche tout simplement :
Item(barcode=5449000000996, description='Coca-Cola 33cl', price=0.7) 3 Coca-Cola 33cl ('Coca-Cola 33cl', 0.7)
L'avantage apporté par les tuples nommés est qu'on peut accéder à leurs attributs directement avec leur nom avec l'opérateur d'accès (.
). On fait donc suivre le nom de la variable du tuple nommé avec le nom de l'attribut, séparé par un point. On peut, par exemple, écrire :