Tuples et dictionnaires¶
Objectifs
Découvrir deux nouvelles structures de données : les tuples et les dictionnaires.
Structures Séquentielles¶
Un structure de données struct
est dite séquentielle si tous ses
éléments ont une unique place numérotée \(i\), appelée indice,
vérifiant \(0\leq i<\mbox{len(struct)}\).
En python, les structures séquentielles disposent (entre autre) des méthodes :
len
index
et leurs éléments peuvent être obtenu grace à leurs indice :
struct[i]
Vous connaissez pour l’instant deux structures séquentielles :
les chaînes de caractères
str
;les listes
list
.
Les chaînes de caractères sont des structures séquentielles de données non mutables de caractères, les listes sont des structures séquentielles de données mutables d’éléments de type quelconque (en Python).
Tuples¶
Les tuples sont un nouveau type de structure de données séquentielle. Comme les listes, les données de ce type peuvent contenir des éléments de type quelconque. Comme les chaînes de caractères, ces données ne sont pas mutables.
Construction en extension¶
On peut construire un tuple en extension, c’est-à-dire littéralement par énumération de ses éléments :
t = (1, 2, 2.52, "Timoleon")
t
est un tuple de longueur quatre. Les indices de ses élèments sont
compris entre 0 et 3 :
len(t)
4
t[0]
1
t[3]
'Timoleon'
Un tuple vide se crée avec une paire de parenthèses :
t = ()
len(t)
0
Il y a un problème pour construire un tuple à un élément, en effet les parenthèses servent également aux expressions arithmétiques. Pour ne pas confondre, on utilise une virgule :
t = (3, )
len(t)
1
Construction avec tuple
¶
On peut également construire un tuple grace au constructeur tuple
.
Il s’agit d’une fonction prenant en paramètre une structure de données
itérable, et qui renvoie un nouveau tuple contenant les éléments de
l’itérable.
t = tuple("Timoléon")
len(t)
8
t[1]
'i'
t[-1]
'n'
Mutabilité des tuples¶
Comme les chaînes de caractères, les tuples ne sont pas mutables : une fois un tuple créé, ne peut modifier ses éléments :
>>> t = (3, 1, 5, 1, 5)
>>> t[2] = 4
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-10-1c3c5480cc1a> in <module>
1 t = (3, 1, 5, 1, 5)
----> 2 t[2] = 4
TypeError: 'tuple' object does not support item assignment
Opérations entre tuples¶
Comme les chaînes de caractères, les tuples disposent des opérations :
concaténation
+
;répétition
*
.
Méthodes sur les tuples¶
Les tuples disposent des méthodes suivantes :
t.index(a)
: renvoie l’indice du premier élément égal àa
;t.count(a)
: renvoie le nombre d’occurrence dea
danst
Affectation multiple¶
Une utilisation intéressante des tuples est l’affectation multiple.
Supposons que l’on dispose d’un tuple t
à deux éléments
t = (3, 7)
Il est possible de déclarer et d’initialiser deux variables a
et
b
avec le contenu de t
, en une seule opération :
(a, b) = t
a
3
b
7
On peut même se dispenser des parenthèses :
c , d = t
c
3
d
7
Cette construction est utile dans les fonctions lorsque l’on souhaite
renvoyer plusieurs valeurs. Il suffit de renvoyer un tuple
contenant
ces valeurs, puis d’utiliser l’affectation multiple.
def mon_divmod(a, b):
"""
:param a: (int) un entier naturel
:param b: (int) un entier naturel
:return: (tuple) le couple (q, r) contenant le quotient et le
reste de la division euclidienne de a par b
:CU: a >= 0, b > 0
:Exemples:
>>> mon_divmod(0,1)
(0, 0)
>>> mon_divmod(26, 7)
(3, 5)
"""
q = 0
r = a - b * q
while r < 0 or r >= b:
q = q + 1
r = a - b * q
return q, r
mon_divmod(26, 7)
(3, 5)
q, r = mon_divmod(26, 7)
q
3
r
5
Structures itérables¶
En Python, une structure de données struct
est dite itérable si on
peut écrire une instruction de la forme :
for a in struct:
...
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-22-86a6f2cfbafd> in <module>
----> 1 for a in struct:
2 ...
NameError: name 'struct' is not defined
Toutes les structures séquentielles sont itérables. Mais il existe des structures itérables qui ne sont pas séquentielles. Nous allons découvrir une telle structure implantée dans python : les dictionnaires.
Les dictionnaires¶
Les dictionnaires sont des structures de données permettant d’associer une valeur à une clé.
Ainsi une liste de couples comme
l = [('banane', 2.59), ('pomme',1.95), ('orange',1.95)]
qui
associe un prix au kg à des fruits, peut être considérée comme une
liste d’association dans laquelle les fruits sont les clés et les prix
les valeurs associées.
Dans un dictionnaire, il ne peut y avoir qu’une seule association pour une clé donnée. Dit autrement, dans un dictionnaire les clés sont uniques.
Constructions¶
Les constructions littérales de dictionnaires sont obtenues par
énumération explicite des associations clé-valeur sous la forme
cle : valeur
, associations séparées par des virgules, le tout entre
accolades.
tarifs = {'banane':2.59, 'pomme':1.95, 'orange':1.95}
tarifs
{'banane': 2.59, 'pomme': 1.95, 'orange': 1.95}
type(tarifs)
dict
Une autre construction possible du même dictionnaire utilise la fonction
dict
.
tarifs = dict([('banane', 2.59), ('pomme',1.95), ('orange',1.95)])
Attention
toute valeur ne peut pas servir de clé. Seules les valeurs non mutables peuvent servir de clé dans une association.
Par exemple, la construction suivante échoue car on tente de construire un dictionnaire avec une association dont la clé est une liste qui est une structure mutable.
{[] : 1}
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-26-1cc35c74f9b5> in <module>
----> 1 {[] : 1}
TypeError: unhashable type: 'list'
Un dictionnaire qui ne contient aucune association est un dictionnaire vide.
Pour obtenir un dictionnaire vide, on peut donner l’expression
{}
{}
ou bien
dict()
{}
Taille d’un dictionnaire¶
La taille d’un dictionnaire, c’est-à-dire le nombre d’associations qu’il
contient, est donnée par la fonction len
.
len(tarifs)
3
Consultation¶
Comme les ensembles, les dictionnaires ne sont pas des structures séquentielles, et leurs éléments ne sont donc pas indexés par des nombres entiers.
En revanche, on accède à la valeur associée à une clé k
dans un
dictionnaire d
grâce à l’expression d[k]
.
tarifs['banane']
2.59
tarifs['orange']
1.95
Toute tentative d’accéder à la valeur associée à une clé qui n’existe
pas se solde par une exception KeyError
.
tarifs['fraise']
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-32-33ca56f7891a> in <module>
----> 1 tarifs['fraise']
KeyError: 'fraise'
Existence d’une association pour une clé donnée¶
On vient de voir que l’accès à la valeur associée à une clé n’existant
pas déclenche une exception. Il peut donc être utile de vérifier
l’existence de la clé dans un dictionnaire. C’est l’opérateur in
qui
permet cette vérification.
'banane' in tarifs
True
'fraise' in tarifs
False
Modification¶
Les dictionnaires sont des structures mutables. On peut modifier la valeur associée à une clé.
Par exemple le prix des bananes baisse.
tarifs['banane'] = 2.30
tarifs
{'banane': 2.3, 'pomme': 1.95, 'orange': 1.95}
Ajout d’une association¶
On peut aussi modifier un dictionnaire en ajoutant une association.
Les fraises arrivent (et sont cheres).
tarifs['fraise'] = 7.5
tarifs
{'banane': 2.3, 'pomme': 1.95, 'orange': 1.95, 'fraise': 7.5}
Suppression d’une association¶
On peut enfin supprimer une association dans un dictionnaire. On le fait
avec l’instruction del
.
del tarifs['fraise']
tarifs
{'banane': 2.3, 'pomme': 1.95, 'orange': 1.95}
Itération¶
Tout commme les listes, les chaînes de caractères, les intervalles et les ensembles, les dictionnaires sont des structures itérables. Il est donc très facile d’effectuer un traitement sur toutes les associations d’un dictionnaire à l’aide d’une boucle pour.
Voici une itération pour imprimer toutes les clés d’un dictionnaire :
>>> for k in tarifs:
print(k)
banane
pomme
orange
et une autre pour imprimer toutes les valeurs associées :
>>> for k in tarifs:
print (tarifs[k])
2.3
1.95
1.95
Attention
Les dictionnaires ne sont pas des structures séquentielles. Il n’est donc pas possible dans un traitement itératif des données contenues dans un dictionnaire de s’appuyer sur un quelconque ordre de ces données.
Quelques applications¶
Représentation de dates¶
Une date peut être représentée de différentes façons. L’une d’elles est
la donnée de trois nombres entiers donnant le jour, le mois et l’année.
Ces trois nombres peuvent être rassemblés dans une liste ou un tuple.
Mais y a-t-il un ordre canonique dans lequel ranger ces trois nombres
dans une liste ou un tuple ? Et une fois cet ordre choisi comment
interpréter une liste ou un tuple de trois entiers ? Par exemple, le
tuple (1,2,3)
représente-t-il le 1er février de l’an 3, ou le 3
février de l’an 1, ou encore l’une des quatre autres interprétations
possibles ?
L’utilisation de dictionnaire permet de nommer les valeurs avec des clés
significatives enlevant toute ambiguïté. Pour représenter la date
d’aujourd’hui, on peut construire un dictionnaire à trois associations
de clés 'jour'
, 'mois'
et 'annee'
.
aujourdhui = {'jour': 25, 'mois': 2, 'annee': 2016}
Une fois choisie une telle représentation des dates, on peut réaliser des fonctions pour obtenir diverses opérations sur les dates. Par exemple une fonction qui calcule la date du lendemain.
>>> lendemain(aujourdhui)
{ 'jour' : 26, 'mois' : 2, 'annee' : 2016 }
Tabulation d’une fonction¶
Les dictionnaires peuvent être utilisés pour tabuler des fonctions.
carres = dict([(k, k*k) for k in range(100)])
On peut désormais utiliser le dictionnaire carres
pour obtenir le
carré de n’importe quel nombre entier compris entre 0 et 99 inclus, sans
avoir à calculer ce carré.
Compter¶
Voici comment il est possible de compter le nombre d’occurrences de chacun des caractères contenus dans une chaîne à l’aide d’un dictionnaire.
s = "la gardienne du campus dessine"
d = dict()
for c in s:
if c in d:
d[c] += 1
else:
d[c] = 1
for c in d:
print(c,':', d[c])
l : 1
a : 3
: 4
g : 1
r : 1
d : 3
i : 2
e : 4
n : 3
u : 2
c : 1
m : 1
p : 1
s : 3