On l'a vu, Python propose 4 types de données de base ( pour rappel : int
, float
, str
et bool
).
A partir de là, il est possible de "construire" ses propres types de données à partir des précédents.
Prenons un exemple : on voudrait stocker dans un script l'ensemble des notes des élèves d'une classe; il faut donc autant de variables qu'il y a de notes, et ce pour chacun des élèves :
Pour un seul élève, ça va encore...
Ensuite, ça ne devient plus gérable...
Il serait alors judicieux de regrouper les notes d'un même élève dans un même ensemble, correspondant à un nouveau type de données appelé par exemple notes
; chaque élève correspondrait alors à une "variable"
différente de ce nouveau type, mais au contraire des types de base, elles stockeraient plusieurs données à la fois, regroupées sous le même nom :
Le type notes
Plusieurs variables du type notes
C'est ce que permettent de faire les p-uplet ( 1-uplet, 2-uplet, 3-uplet..., p étant le nombre d'éléments stocké(s) ) et les tableaux.
Ils correspondent en informatique à un ensemble de données ( une "collection" ), rassemblées de façon à pouvoir y accéder facilement. Chaque donnée correspond à un élément différent de l'ensemble.
Dans de nombreux langages, ces éléments doivent être du même type, mais ce n'est pas le cas en Python : on peut mettre dans un p-uplet ou un tableau Python des données de type différent, mais c'est à éviter
pour des raisons de lisibilité.
Chaque élément d'un tuple ou tableau correspond donc à une "case" dans laquelle on placerait une donnée. L'ordre dans lequel les données sont rangées permettra alors de les retrouver en désignant la bonne "case" dans laquelle elle est contenue.
45 | 3.2 | 27.246 | 'truc' | 78 | 'bidule' | 423 | 785 | 2.3 | 7.896 | True | ... |
En Python, les p-uplet sont implémentés avec le type tuple
.
Les tableaux sont eux implémentés à l'aide du type de données list
, appelé liste Python, mais il s'agit d'un nom qui peut prêter à confusion, car une "liste" en informatique correspond
à un concept bien différent du tableau ( concept que vous verrez d’ailleurs en Terminale si vous continuez la spécialité NSI ).
Il y a des raisons pour que les concepteurs du langage Python aient quand même choisi le nom "liste" pour désigner les tableaux, mais nous ne nous étendrons pas là-dessus.
Nous utiliserons dorénavant toujours le mot "tableau" pour désigner ce type de données, mais ne vous étonnez pas de trouver le mot "liste" dans d'autres cours ou sur Internet.
La grosse différence entre tuple et tableau est la suivante :
(1, 6, 8, 11)
.[1, 6, 8, 11]
.Un tableau ou un tuple a un nom : ce nom est commun à l'ensemble des données stockées dans le tuple ou le tableau; on le choisit arbitrairement, mais comme pour les variables, il y a certaines restrictions dans ce choix : on ne peut pas utiliser
les termes du langage Python lui-même, le nom ne doit pas commencer par un chiffre ni un caractère autre qu'une lettre, il ne doit pas y avoir d'espace,...
On peut utiliser des lettres majuscules, sauf au début du nom.
Chaque élément d'un tuple ou d'un tableau est repéré par son indice ( ou index ), qui représente la position de la donnée stockée ( en gros, le numéro de la "case" où la donnée est stockée ) depuis le début du tuple ou tableau.
Attention : comme beaucoup de choses en informatique ( comme par exemple les chaînes de caractères ), la numérotation des indices commence non pas à 1 mais à 0 : la première donnée a l'indice 0, la deuxième l'indice 1, la troisième 2, etc....
Indice | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
Valeur | 45 | 3.2 | 27.246 | 45.6 | 78 | 12 | 423 | 785 | 2.3 | 7.896 | 5 |
Pour adresser un élément particulier du tuple/tableau, on utilise alors la syntaxe suivante :
nom_du_tableau[indice_de_l_element]
...qui désigne alors la valeur stockée dans l'élément adressé.
Bien entendu, il faut que l'indice soit bien dans les limites "permises" du tableau, c'est à dire être compris entre 0 ( indice du premier élément ) et n - 1 ( n = nombre d'éléments du tableau ).
--------------------------------------------- | indices | 0 | 1 | 2 | 3 | ... | n-2 | n-1 | --------------------------------------------- | valeurs | . | . | . | . | ... | . | . | ---------------------------------------------
Dans le cas où l'on "sort" du tableau, Python signale une erreur IndexError : Index out of range
( que vous rencontrerez de trop nombreuses fois !! )
Exemples pour le tuple/tableau ci-dessus, nommé tup_tab :
tup_tab[0] == 45
tup_tab[3] == 45.6
tup_tab[8] == 2.3
tup_tab[12] → IndexError !
C'est donc tout à fait le même "mode de fonctionnement" que les chaînes de caractères...
Attention, une erreur classique est de confondre l'indice d'un élément dans le tuple ou le tableau, et la valeur stockée dans cet élément.
Pour simplifier :
Pour afficher un élément d'un tuple/tableau, utiliser la syntaxe précédente :
>>> print(tup_tab[8])
2.3
>>> print(tup_tab[3])
45.6
Pour afficher le tuple/tableau complet, utiliser son nom général :
>>> print(tup_tab)
[45, 3.2, 27.246, 45.6, 78, 12, 423, 785, 2.3, 7.896, 5] # ou (45, 3.2, 27.246, 45.6, 78, 12, 423, 785, 2.3, 7.896, 5) si c'est un tuple !
Pour trouver le nombre d'éléments présents dans un tuple ou un tableau, utiliser l'instruction len()
:
>>> print(len(tup_tab))
11
Comme on l'a dit plus haut, cela n'est possible qu'avec les tableaux et pas les tuples.
Jusqu'à maintenant, vous avez vu des types de données ( int
, float
, str
,...et maintenant tuple
) qui sont immuables : cela
signifie que les variables de ces types ne peuvent pas être modifiées; la seule façon de les "réutiliser" est en fait de leur
réaffecter une nouvelle valeur, ce qui se traduit en réalité par la création d'une nouvelle variable portant le même nom, "l'ancienne" étant effacée de la mémoire :
Pour visualiser cela, nous allons utiliser la fonction Python id(variable)
, renvoyant l'identifiant unique d'une variable, qui est différent pour des variables différentes :
Les tableaux sont eux au contraire muables ( mutable en anglais ) : cela signifie que l'on peut en modifier un élément sans avoir à complètement réaffecter au tableau de nouvelles données :
On dit dans ce cas que l'on modifie un tableau par mutation ( et donc pas par réaffectation ); dans ce cas, Python n'a alors pas besoin de créer une nouvelle variable.
Bien entendu, rien n'empêche cependant de réaffecter à une variable un tableau complètement nouveau !
Ce mode de fonctionnement est bien pratique, mais peut entraîner des problèmes, par exemple lors de la copie d'un tableau, problèmes que nous évoquerons plus tard.
On rappelle que concaténer signifie "ajouter à la suite de".
Comme pour les chaînes de caractère, l'opérateur +
permet de concaténer deux tableaux en un plus grand :
tableau1 = [1 , 2 , 3]
tableau2 = [4 , 5 , 6]
tableau1 = tableau1 + tableau2 # on pourrait si on voulait créer aussi un troisième tableau
print(tableau1)
[1 , 2 , 3 , 4 , 5 , 6]
C'est la seule méthode pour créer un tuple. On décrit l'ensemble des éléments, séparés par des virgules; la syntaxe change pour les tuples et les tableaux :
tableau1 = [45, 32, 27, 189, 78, 569, 423, 785, 23, 78, 630] # utilisation de crochets pour les tableaux
noms = ('durand', 'martin', 'roger', 'paul', 'dubois', 'jean') # utilisation de parenthèses pour les tuples
Vous aurez parfois besoin d'initialiser un tableau vide, c'est à dire n'ayant aucun élément :
tableau_vide = []
Pour remplir automatiquement un tableau avec un nombre donné d'éléments tous identiques :
tableau1 = [None]*100 # crée un tableau contenant 100 éléments tous égaux à None
( = "rien" )
tableau2 = [0]*10 # crée un tableau contenant 10 éléments tous égaux à 0
( Vous aviez déjà vu cette façon de faire avec les chaînes de caractères...)
La première idée est de créer un tableau ayant un certain nombre d'éléments de valeur quelconque dans un premier temps ( None
par exemple, qui signifie "rien" ), et de "remplir" ensuite chaque "case" avec une valeur :
tab = [None]*10 # création d'un tableau de 10 éléments tous égaux à 'None'
for i in range(10):
tab[i] = 2**i # "remplit" chaque élément avec une puissance croissante de 2
print(tab)
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
A partir d'un tableau ne contenant initialement aucun élément ( = tableau vide ), on "ajoute" les éléments les uns après les autres à la fin du tableau qui se construit donc petit à petit; pour
cela, on utilise une méthode particulière associée aux listes Python, la méthode append
:
tab = [] # tableau vide
for i in range(10):
tab.append(2**i) # "append" = "ajouter à la fin"
Il existe une autre syntaxe, équivalente à la précédente : :
tab = []
for i in range(10):
tab = tab + [2**i]
Mais vous verrez en Terminale qu'elle est moins efficace que la précédente : on préférera donc utiliser la méthode append
.
Attention, méthode très puissante, mais pas évidente à maîtriser. Mais elle est au programme et sera dorénavant très utilisée !
C'est une méthode de création de tableau équivalente aux deux précédentes, mais en beaucoup plus concis :
tableau1 = [i for i in range(10)] # crée un tableau contenant 10 éléments de 0 à 9
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>
tableau2 = [2*i for i in range(10)] # crée un tableau contenant 10 éléments, chaque élément étant le double du compteur i
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>>
tableau3 = [2*i for i in range(10) if i%3 == 0 ] # crée un tableau contenant les éléments double du compteur i, mais uniquement si i est divisible par 3
[0, 6, 12, 18]
>>>
L'expression peut être plus ou moins complexe selon ce que l'on veut faire ! On peut même y mettre des conditions complexes, des boucles imbriquées, etc...
Pour déterminer l'indice d'une valeur particulière dans un tuple ou un tableau ( ça peut servir...), utiliser la fonction index() :
>>>tableau4 = ['lundi','mardi','mercredi','jeudi','vendredi','samedi','dimanche']
>>> print(tableau4.index('mercredi'))
2
Attention si il y a des doublons : la fonction méthode()
ne donne que l'indice du premier élément rencontré ayant la valeur recherchée.
Si la valeur cherchée n'est pas dans le tableau, une erreur est renvoyée.
On peut tester la présence de telle ou telle valeur dans un tuple ou un tableau en utilisant l'opérateur in
:
if 45 in tup_tab : # renvoie True
print("Valeur présente")
if 214 in tup_tab : # renvoie False
print("Valeur absente")
Vous venez de voir que les tableaux sont bien plus "souples" que les tuples, et vous en viendrez alors vite à vous demander quel est l'intérêt de ces derniers : pourquoi ne pas toujours utiliser des tableaux ?
Il faut bien voir que leur stockage en mémoire n'est pas du tout le même :
On aura donc intérêt à utiliser les tuples quand on n'aura à stocker que des données constantes au cours d'un programme.
Les tuples sont également mis en œuvre lorsqu'une fonction doit renvoyer plusieurs résultats.
Voila par exemple la définition d'une fonction qui calcule et renvoie le quotient et le reste de la division entière de deux entiers :
def division_entiere(n1:int, n2:int) -> int:
quotient = n1 // n2
reste = n1 % n2
return quotient, reste # renvoi des deux valeurs sous forme d'un tuple ( les parenthèses sont optionnelles dans cette situation )
Les deux résultats quotient et reste sont renvoyés sous forme d'un tuple au programme principal.
Il faudra donc penser que le type de la variable utilisée lors de l'appel de la fonction depuis le programme principal sera un tuple :
resultat = division_entiere(146, 78) # affectation du résultat renvoyé par la fonction au tuple 'resultat'
print("Le quotient est égal à", resultat[0])
print("Le reste est égal à", resultat[1])
On peut également récupérer les deux résultats du tuple...directement dans un tuple de deux éléments :
quotient, reste = division_entiere(146, 78) # affectation du résultat renvoyé au tuple (quotient, reste) ( là non plus, les parenthèses ne sont pas obligatoires )
# bien entendu, les éléments de ce tuple doivent être dans le même ordre que celui de la fonction !
print("Le quotient est égal à", quotient)
print("Le reste est égal à", reste)
Vous rencontrerez assez souvent des fonctions renvoyant des tuples de plusieurs résultats, faites attention quand c'est le cas !
Définir le tableau [17, 38, 10, 25, 72]
en lui donnant un nom, puis effectuez les actions suivantes :
Créer à l'aide d'une boucle , puis afficher les tableaux suivants :
randint(a,b)
du module random
).[0, 1, 0, 1, 0, ...]
).for i in range(...)
)[1, -1, 1, -1, 1, ...]
). Vous pourrez utiliser astucieusement l’indice de la boucle... mais il existe de nombreuses autres approches !Reprendre les exercices précédents mais en utilisant cette fois la méthode de création par compréhension.
Les tableaux et les tuples sont des types de données, ils peuvent donc très bien être utilisés comme paramètre/argument de fonction, ou alors de résultat renvoyé par une fonction.
moyenne_annuelle
ci-dessous qui prend en paramètre un tuple de trois nombres flottants compris entre 0 et 20 et renvoie la moyenne de ces trois nombres.moyenne_annuelle((12, 13, 14)) == 13
moyenne_annuelle((8, 13, 14)) == 11.666666666666666
moyenne_annuelle((0, 5, 16)) == 7
moyenne_annuelle((12.54, 13.12, 14.58)) == 13.413333333333332
moyenne_annuelle((12.99, 17.21, 15.84)) == 15.34666666666667
Le cadavre exquis est un « jeu qui consiste à faire composer une phrase, ou un dessin, par plusieurs personnes sans qu'aucune d'elles ne puisse tenir compte de la collaboration ou des collaborations précédentes.»
La méthode randint(a, b)
du module random
permet de tirer un nombre entier au hasard entre deux bornes a et b incluses.
A vous de réfléchir ici à comment l’utiliser pour "tirer" au hasard un élément dans un tableau : quelles sont les bornes a et b à indiquer ?
cadavre_exquis
ci-dessous qui prend en paramètres :
Dans cet exercice, une fonction doit créer un tableau et le renvoyer.
Pour la création du tableau, choisir la méthode que vous préférez !! ( n'oubliez pas qu'il faut toutes les connaître..)
On lance successivement cinq dés à six faces et on souhaite mémoriser les résultats obtenus dans un tableau.
lancer_cinq_des
ci-dessous afin qu'elle renvoie un tableau contenant les résultats aléatoires de cinq lancers de dés..lancer_n_des
qui prend en paramètre un nombre entier positif n et renvoie un tableau de longueur n correspondant
au résultat d'un lancer de n dés. Pour cela, on adaptera la fonction précédente.Écrire une fonction qui prend comme paramètre une date sous la forme jj//mm/aaaa ( par exemple : 19/11/2024
), et qui renvoie cette date sous une forme plus "parlante", comme :
19 novembre 2024.
Il existe une méthode en Python, la méthode split
, qui sépare les mots d'une chaîne de caractères, selon un caractère de séparation que l'on peut éventuellement préciser
( par défaut, c'est l'espace ), et qui renvoie le tableau de ces mots :
"salut les amis".split() # le caractère de séparation est éventuellement passé en argument
>>> ["salut", "les", "amis"]
On pourra utiliser avec profit un tuple pour stocker les noms des différents mois, et s'en servir pour faire la "conversion" :
mois = ("janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre")
Tester la fonction avec plusieurs dates.
On souhaite écrire une fonction partage_tableau
qui :
Exemple : partage([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 4)
renvoie : [1, 2, 3, 4, 5], [6, 7, 8, 9, 10]
Si vous êtes efficaces, votre fonction peut tenir en 3 lignes...
On souhaite écrire un programme, qui détermine les deux valeurs, dans un tableau de valeurs entières et uniques dans le tableau, dont la somme est égale à un total donné.
Par exemple, dans le tableau : [2, 6, 5, 3, 8]
, les deux valeurs dont la somme est égale à 9 sont : 6 + 3 = 9.
Le principe est le suivant :
[1, 3, 4, 6, 7, 8, 10, 11, 13, 17, 18, 23, 24, 30, 38, 39, 41, 50]
, dont la somme est égale
à 46.somme_total
ci-dessous, qui prend comme paramètres un tableau tab de valeurs entières et triées, et une valeur entière total, et renvoie les indices gauche et droite
des éléments dans tab dont la somme est égale à total.