1NSI : cours Tuples Python⚓︎
Introduction⚓︎
Tuples
Un
C'est une structure de données primitive de Python, qui est un type construit donc un conteneur/collection d'éléments.
Les types des éléments d'un tuple :
- peuvent être variables pour certains langages, dits à typage dynamique (Python, ..),
- ou pas, pour certains autres langages, dits à typage statique (langage C, Java, etc..)
Exp
On définit un tuple
avec des parenthèses ()
>>> t = (2,3,7,5.4,"Bonjour")
Fonctions utiles sur les Tuples⚓︎
Longueur d'un tuple⚓︎
>>> t = (4,3,6.1,8,5,10)
>>> len(t) # renvoie le nombre d'éléments/objets du tuple
len
renvoie la longueur du tuple
Tuple Vide⚓︎
>>> t = () # est le tuple 'VIDE' qui est de type 'tuple',
# et qui ne contient aucun élément
>>> len(t)
0 # la longueur du tuple vide vaut 0
ou bien (équivalent pour définir un tuple vide) :
>>> t = tuple()
Tuple à un unique élément⚓︎
>>> t = (2,) # est le tuple contenant l'unique élément '2',
# et qui ne contient aucun autre élément
>>> len(t)
1 # la longueur du tuple vide vaut 0
>>> t = (2) # N'EST PAS UN TUPLE
# c'est un ENTIER 'int' qui vaut 2,
Appartenance à un Tuple avec in
, ou pas, avec not in
⚓︎
>>> t = (8,2,6,1,3,4,5)
>>> 2 in t
True
>>> 7 in t
False
>>> (1,3) in t
False
>>> t = (8,2,6,(1,3),4,5)
>>> (1,3) in t
True
# ou bien NON appartenance avec les mots-clés `not in`
>>> 2 not in t
False
Indices / Index⚓︎
Indices positifs⚓︎
>>> t = (6,5,2,7.4,"Bonjour")
>>> t[4] # renvoie l'élément à l'indice 4, ici: "Bonjour"
>>> t[0] # renvoie le 1er élément = l'élément à l'indice 0
Indices négatifs⚓︎
>>> t[-1] # renvoie le dernier élément
>>> t[-2] # renvoie l'avant-dernier élément
Tranches / Slices ou Slicing⚓︎
Tranches / Slicing simple (avec 2 arguments)⚓︎
>>> t=(8,7,2,5,10,16,6,3,18)
>>> t[3:7] # renvoie tous les éléments dont les indices
# sont compris entre 3 inclus
# et 7-1=6 inclus (donc 7 NON inclus)
Tranches / Slicing étendu (avec un 3ème argument pas/step optionnel)⚓︎
>>> t[3:6:2] # renvoie tous les éléments dont les indices
# sont compris entre 3 inclus
# et 5 inclus (c'est-à-dire 6 NON inclus)
# mais seulement tous les 2 éléments, avec un pas=2
Exp
>>> t[:6:2] # tous les éléments depuis le tout début
# jusqu'à celui d'indice 5 inclus (c'est-à-dire 6 NON inclus)
# mais seulement tous les 2 éléments, avec un pas=2
>>> t[3::2] # tous les éléments depuis celui d'indice 3 inclus
# jusqu'à la toute fin du tuple
# mais seulement tous les 2 éléments, avec un pas=2
>>> t[::2] # tous les éléments depuis le tout début
# jusqu'à la toute fin du tuple
# mais seulement tous les 2 éléments, avec un pas=2
>>> t[::-1] # tous les éléments depuis le tout début
# jusqu'à la toute fin du tuple
# avec un pas=-1, donc écrit à l'envers...
>>> t[5:2:-1] # tous les éléments depuis celui d'indice 5
# jusqu'à celui d'indice 2 NON INCLUS
# avec un pas=-1, donc écrit à l'envers...
Les Tuples sont des séquences⚓︎
Les tuples disposent d'indices entiers, et d'une fonction len()
donc :
Pte
Les tuples tuple
sont des séquences.
Techniques de parcours de Tuples⚓︎
Technique 1 : élément par élément, SANS indices⚓︎
t = (8,6,9,5,3,10,2,4,7)
for element in t:
print(element)
Pte
Les tuples tuple
sont des itérables.
Technique 2 : élément par élément, AVEC des indices⚓︎
t = (8,6,9,5,3,10,2,4,7)
for i in range(len(t)):
print(t[i])
Les tuples sont des séquences, donc ils sont itérables.
Utilisation des Tuples pour stocker des Tableaux de Nombres /Matrices⚓︎
Disons que l'on souhaite stocker en mémoire la matrice de nombres
A = 1 4 6 8
-2 3 5 -1
8 10 9 7
Comment faire? Quel type de données utiliser?
>>> A = ((1,4,6,8),(-2,3,5,-1),(8,10,9,7))
Du coup, comment accéder à chacun des éléments du Tableau à 2 Dimensions?
Par exemple, pour accéder à l'élément 4
, il faut taper la ligne commande/l'instruction:
>>> A[0][1]
Ex
Quelles instructions faut-il taper pour accéder aux éléments suivants?
- 3? 5? 8? 7?
>>> A[1][1] = 3
>>> A[1][2] = 5
>>> A[2][0] = 8
>>> A[2][3] = 7
Lorsqu'on dispose d'un tuple de sous-tuples, de dimension 2 (par exemple le tuple A de l'exercice précédent). Dans ce cas:
A[i][j]
représente l'élément situé :
- à la ligne d'indice
i
- à la colonne d'indice
j
Méthodes sur les Tuples⚓︎
(PRESQUE) PAS de méthodes sur les Tuples⚓︎
Les tuples
n'ont (presque) pas de méthodes :
- On ne peut PAS ajouter d'élément à un
tuple
: Les tuples n'ont PAS de méthodest.append()
, nit.extend()
- On ne peut PAS enlever d'éléments d'un
tuple
: Les tuples n'ont PAS de méthodest.remove()
out.pop()
. L'immense majorité des méthodes sur les listes n'existent tout simplement PAS sur les tuples.
Par contre, le mot-clé in
permet de détecter si un élément appartient à un tuple, ou pas : element in t
Seulement 2 méthodes sur les tuples : count()
et index()
⚓︎
Les tuples
disposent tout de même deux méthodes seulement : count()
et index()
Notons t
un tuple.
t=(1,5,3,7,2,1,2,3,2,4,2,8)
t.count(3)
compte le nombre d'occurences de3
dans le tuplet
-
t.index(2)
renvoie :- le 1er indice où se trouve
2
dans le tuplet
- ou bien une erreur s'il ne trouve PAS
2
dans le tuplet
Forme Générale:
t.index(el,[,start[,end]])
cherche la 1ère occurence deel
dans le tuplet
, pour des indices compris entrestart
(etend
) - le 1er indice où se trouve
- Les tuples sont plus rapides que les listes. Si vous définissez un ensemble constant de valeurs et que tout ce que vous allez faire est le parcourir, utilisez un tuple au lieu d'une liste.
- le code est plus sûr : si on "protège en écriture" les données qui n'ont pas besoin d'être modifiées. Utiliser un tuple à la place d'une liste revient à avoir une assertion implicite que les données sont constantes et que des mesures spécifiques sont nécéssaires pour modifier cette définition.
- les clés de dictionnaire peuvent être des entiers, des chaînes ou des
tuples
En fait, c'est plus compliqué que ça : - Les clés de dictionnaire doivent être immutables.
- Les tuples sont immutables, donc ils peuvent être utilisés comme clés de dictionnaire.
mais attention, plus précisément :
- Si on a un tuple contient des listes, alors il est considéré comme mutable et n'est pas utilisable comme clé de dictionnaire.
- Par conséquent : Seuls les tuples de chaînes, de nombres ou d'autres tuples peuvent être utilisés comme clé de dictionnaire.
- Les tuples sont utilisés pour le formatage de chaînes
Liste Complète des Méthodes sur les Tuples⚓︎
Aide en ligne⚓︎
La documentation officielle n'est pas d'un grand secours sur ce point.
Aide en Local (dans un Interpréteur Python)⚓︎
-
Dans un interpréteur Python,
dir(tuple)
affiche la liste complète de toutes les méthodes disponibles sur lestuple
, y compris les méthodes magiques/spéciales (cf ci-dessous), mais elles ne sont pas documentées (ni signature, ni docstring). -
Dans un interpréteur Python,
help(tuple)
affiche la liste complète de toutes les méthodes disponibles sur lestuple
, y compris les méthodes magiques/spéciales (cf ci-dessous), AVEC DOCUMENTATION: AVEC LEURS SIGNATURES ET LES DOCSTRINGS.
Méthodes magiques / Méthodes spéciales sur les Tuples⚓︎
Méthodes magiques / Méthodes spéciales sur les Tuples
Parmi toutes les méthodes disponibles affichées par dir(list)
, certaines sont encadrées par deux underscores (de chaque côté) __unCertainNom__()
: Elles sont appelées des
- elles sont accessibles via la syntaxe normale pour les méthodes :
nomTuple.__nomMethodeMagique__()
- elles sont également accessibles via une syntaxe spéciale / magique (qui dépend de la méthode en question)
de Méthodes magiques / Méthodes spéciales sur les Tuples
On se donne deux tuples t1=(1,2,3,4)
et t2=(5,6,7)
__len()__
: calcule la longueur d'un tuple ...- Syntaxe normale :
t2.__len__()
renvoie le nombre \(3\) - Syntaxe spéciale :
len(t2)
renvoie le nombre \(3\)
- Syntaxe normale :
-
- Syntaxe normale :
t1.__eq__(t2)
renvoieFalse
cart1
ett2
ne sont pas égaux - Syntaxe spéciale :
t1 == t2
renvoieFalse
(pour les mêmes raisons)
__eq()__
: teste l'égalité entre deux tuples ...Principe Général : À chaque fois qu'on veut tester l'égalité entre deux tuples avec le symbole
==
, c'est en fait la méthode magique__eq__()
qui est appelée pour tester l'égalité. - Syntaxe normale :
Voici quelques autres méthodes magiques sur les tuples :
__ne__()
veut dire \(\ne\) : "Not Equal to" c'est-à-dire Non égal, donc! =
en Python__gt__()
veut dire \(\gt\) : "Greater Than" c'est-à-dire Supérieur Strictement__ge__()
veut dire \(\ge\) : "Greater than or Equal to" c'est-à-dire Supérieur ou égal à__lt__()
veut dire \(\lt\) : "Less Than" c'est-à-dire Inférieur Strictement__le__()
veut dire \(\le\) : "Less than or Equal to" c'est-à-dire Inférieur ou égal__add__()
correspond à l'opération+
: pour la concaténation de deux tuples__mul__()
correspond à l'opération*
: pour la multiplication entre une tuple et un entier__contains__()
correspond au mot-cléin
utilisé pour tester l'inclusion d'un tuple dans un autre__repr__()
représente un tuple dans un interpréteur Python, c'est-à-dire qu'il affiche un tuple dans un interpréteur Python, sous un certain format spécifique. Elle est appelée quand on tape dans l'interpréteur :
- ou bien
>>> t1
\(\quad\) (oùt1
désigne le nom d'un tuple) - ou bien
>>> print(t1)
- ou bien
__str__()
représente un tuple dans un interpréteur Python, c'est-à-dire qu'il affiche un tuple dans un interpréteur Python, sous un certain format spécifique, mais seulement pour le
print()
>>> print(t1)
- etc...
Opérations Arithmétiques sur les Tuples⚓︎
Addition⚓︎
>>> t1 = (4,6,8)
>>> t2 = (3,5,7,9)
>>> t1 + t2 # ceci est la CONCATÉNATION de t1 et t2
(4,6,8,3,5,7,9)
ATTENTION : Pas de Soustraction
Multiplication⚓︎
>>> t1 = (4,6,8)
>>> t1 * 2
(4, 6, 8, 4, 6, 8)
ATTENTION :
- le produit de deux tuples n'existe pas
- Pas de Division entre deux tuples
Les tuples sont immutables⚓︎
Par exemple, on NE peut PAS modifier directement un élément d'un tuple
in situ, par affectation directe (EN CONSERVANT LA MÊME ADRESSE MÉMOIRE, qui est en fait un pointeur vers le début du tuple).
On dit que les tuples NE supportent PAS l'affection d'éléments ou les item assignment
:
>>> t = (4,3,6,8,5,10)
>>> id(l) # renvoie l'adresse mémoire du début du tuple
# Exemple de réponse:
140034881798976
# affectation d'élément / item assignment IMPOSSIBLE :
>>> l[1] = 7
TypeError: 'tuple' object does not support item assignment
Plus généralement, on NE peut PAS modifier le contenu d'une variable de type tuple in situ, c'est-à-dire EN CONSERVANT LA MÊME ADRESSE MÉMOIRE: Pour commencer, parce qu'il n'existe aucune méthode sur les tuples...
>>> t = (1,2)
>>> id(t) # renvoie l'adresse mémoire du début du tuple
# Exemple de réponse:
140289038997760
# 'ajout' d'élément en fin de tuple :
>>> t = t + (3,4)
>>> id(t) # la 'nouvelle' adresse mémoire du tuple, après modification
# (ici, ajout d'élément en fin de tuple), est MODIFIÉ
140289037769280
On s'aperçoit que les deux adresses mémoires, ou pointeurs, AVANT et APRÈS modification du tuple, NE SONT PLUS égales.
ImMutabilité des Tuples
Les tuples sont immutables.
Compréhensions de Tuples⚓︎
Une compréhension de tuple, ou tuple en compréhension, est une syntaxe pour créer/générer un tuple en une seule ligne de commande, en y incluant une boucle for sur une seule ligne.
Syntaxe sans if
⚓︎
# 'iterable' désigne un itérable: une chaîne, une liste, ou un tuple (etc...)
tuple(fonction(item) for item in iterable)
Exp
>>> tuple(i for i in range(10))
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
>>> tuple(i for i in "Bonjour maman")
('B', 'o', 'n', 'j', 'o', 'u', 'r', ' ', 'm', 'a', 'm', 'a', 'n')
tuple(...)
provoque le renvoi d'un générateur ou generator
au lieu de renvoyer un
tuple
:
>>> (i for i in range(10))
<generator object <genexpr> at 0x7f740577b4a0>
- En Python, les générateurs ont été créés afin de simplifier la création d'itérateurs.
Les générateurs utilisent un mot magique :
yield
- En Python, les itérateurs sont des objets dits itérables, c'est-à-dire des objets sur lesquels on peut itérer, comprendre faire des itérations sur ses éléments, par exemple avec une boucle
for
.
Syntaxe avec un if
⚓︎
# 'iterable' désigne un itérable: une chaîne, une liste, ou un tuple (etc...)
tuple(fonction(item) for item in iterable if condition(item))
Exp
# tuple de tous les nombres de 0 à 20 inclus, sauf les multiples de 4
>>>> tuple(i for i in range(21) if i%4!=0)
(1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15, 17, 18, 19)
if
DOIT être placé APRÈS le for
, du moins lorsque le if
est tout seul (c'est-à-dire non accompagné d'un else
). En particulier, la syntaxe suivante, que l'on pourrait naïvement croire équivalente, NE FONCTIONNE PAS:
>>> tuple(i if i%4!=0 for i in range(21))
SyntaxError: invalid syntax
Syntaxe avec un if
ET un else
⚓︎
# 'iterable' désigne un itérable: une chaîne, une liste, ou un tuple (etc...)
tuple(fonction(item) if condition(item) else autreFonction(item) for item in iterable)
Exp
# tuple de tous les nombres de 0 à 20 inclus, sauf les multiples de 4 qui sont quant à eux remplacés par "bissextile"
>>> tuple(i if i%4!=0 else "bissextile" for i in range(21))
('bissextile', 1, 2, 3, 'bissextile', 5, 6, 7, 'bissextile', 9, 10, 11,
'bissextile', 13, 14, 15, 'bissextile', 17, 18, 19, 'bissextile')
if
DOIT être placé APRÈS le for
, du moins lorsque le if
est tout seul (c'est-à-dire non accompagné d'un else
). En particulier, la syntaxe suivante, que l'on pourrait naïvement croire équivalente, NE FONCTIONNE PAS:
>>> tuple(i for i in range(21) if i%4!=0 else "bissextile")
SyntaxError: invalid syntax