Aller au contenu

1NSI : cours Tuples Python⚓︎

Introduction⚓︎

Tuples

Un Tuple est un conteneur (non modifiable/immutable) d'éléments ordonnés.

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

ATTENTION : ERREUR CLASSIQUE

>>> 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

Remarque
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éthodes t.append(), ni t.extend()
  • On ne peut PAS enlever d'éléments d'un tuple : Les tuples n'ont PAS de méthodes t.remove() ou t.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 de 3 dans le tuple t
  • t.index(2) renvoie :

    • le 1er indice où se trouve 2 dans le tuple t
    • ou bien une erreur s'il ne trouve PAS 2 dans le tuple t

    Forme Générale: t.index(el,[,start[,end]]) cherche la 1ère occurence de el dans le tuple t, pour des indices compris entre start (et end)

Mais alors : à quoi servent donc les tuples ?

  • 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)⚓︎

  1. Dans un interpréteur Python, dir(tuple) affiche la liste complète de toutes les méthodes disponibles sur les tuple, y compris les méthodes magiques/spéciales (cf ci-dessous), mais elles ne sont pas documentées (ni signature, ni docstring).

  2. Dans un interpréteur Python, help(tuple) affiche la liste complète de toutes les méthodes disponibles sur les tuple, 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 méthodes magiques ou méthodes spéciales sur les tuples. En pratique cela signifie que :

  • 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 : t1.__eq__(t2) renvoie False car t1 et t2 ne sont pas égaux
    • Syntaxe spéciale : t1 == t2 renvoie False (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é.

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)
  • ⚠ __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.

Remarque Le fait que les tuples soient immutables laisse à penser qu'il s'agit d'un type (/structure) de données Python qui n'est PAS prévu pour être modifié régulièrement avec une bonne efficacité.

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')

ATTENTION L'oubli du mot-clé 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)

REMARQUE / ATTENTION Le 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')

REMARQUE / ATTENTION Le 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