Dict : Type associatif
Essayons d'écrire un petit programme d'annuaire :
- On peut renseigner un nouveau contact en donnant son nom et son adresse mail.
- On peut consulter l'adresse mail d'un contact en donnant son nom.
- Si on renseigne un contact déjà enregistré, son adresse mail est mise à jour mais un nouveau contact n'est pas créé.
Un problème dans les séquences...
Activité
Expliquez comment faire un tel programme avec des types séquences.
Expliquez également pourquoi cette solution pose problème.
EXPOSEZ VOS REPONSES A VOTRE PROF
L'annuaire comme une liste de paires :
[ ("Félix", "unmail@unboite.com"), ("Julie", "unautremail@uneautreboite.com"), ("Mathilde", "mathilde@uneboite.com"), ("NOM", "MAIL"), ...]
Mais cette solution rends tout très compliqué :
Pour savoir l'adresse de Félix, il faut chercher Félix dans la liste !
Si on veut ajouter un contact, il faut d'abord le chercher pour vérifier qu'il n'est pas déjà dans la liste, sinon il faut le mettre à jour et non l'ajouter.
Heureusement, Python a une solution très pratique pour ça !
Dict : type associatif
Python propose un type, dict, ou dictionnaire, spécialisé dans les associations par paires.
On construit un dictionnaire en spécifiant des paires, entre {} :
Dans une paire, par exemple
On dit que"Félix" est la clé et que "f@mail.com" est la valeur.
On peut très facilement tester si une clé est dans un dictionnaire avec l'opérateur in :
Si la clé est dans le dictionnaire, on peut retrouver la valeur qui lui est associée avec l'opérateur [] :
On peut ajouter une nouvelle paire dans le dictionnaire de la manière suivante :
Si la clé est déjà présente dans le dictionnaire, alors la valeur associée est mise à jour :
un_dico = {"Félix" : "f@mail.com"}
print(un_dico["Félix"]) #affiche f@mail.com
un_dico["Felix"] = "felfel@mail.fr"
print(un_dico["Félix"]) #affiche felfel@mail.fr
Donc, les clés dans un dictionnaire sont uniques : il ne peux y avoir qu'une seule clé avec une valeur donnée.
Activité
Implémentez un programme qui :
- Propose à l'utilisateur de renseigner des contacts tant qu'il ne rentre pas une chaine vide.
- Propose ensuite à l'utilisateur de retrouver le mail d'un contact à partir de son nom, encore et encore, tant qu'il ne rentre pas une chaîne vide.
TODO : ajouter solution
On peut parcourir les clés d'un dictionnaire avec un for ... in ...:
Vous pouvez avoir la liste des clés dans un dictionnaire en utilisant keys ou en le convertissant en liste :
Vous pouvez avoir la liste des valeurs dans un dictionnaire en utilisant values:
Activité
Modifiez le programme de l'activité précédente pour que si l'utilisateur se trompe demande l'adresse d'un contact qui n'existe pas, la liste des contacts lui soit affichée.
TODO : ajouter solution
Usages et typages
Le dictionnaire a deux utilités.
La première est celle que nous avons vue dans la section précédente : enregistrer un nombre indéterminé de paires, où toutes les clés ont le même type et la même signification, et toutes les valeurs le même type et la même signification. Il remplace donc une liste de paires. Par exemple :
La seconde est de donner du sens à des valeurs en nombre fixe, comme nous avions vu pour les tuples. Dans ce cas là, les clés sont des chaînes de caractère qui donnent le sens de leur valeurs associées, et les valeurs peuvent avoir n'importe quels types :
personne = {
"nom" : "Bertoni", #type : str
"prénom" : "Félix", #type : str
"age" : 29, #type int
"niveau" : 200, #type int
"diplomes" : ["BAC", "DUT", "Ingenieur", "DIU"] #type list[str]
}
Activité
TODO ajouter activité ici : ptet ajouter des info supplémentaire dans le dico ?
Extension : dispatching dynamique
Cette section est une extension, elle est donc optionnelle. Il est quand même intéressant d'y jeter un oeil, même si vous ne la faites pas.
Les dictionnaires sont un outils extrêmement puissant.
Parfois, une série de if...else peut être remplacée par un simple dictionnaire. Et c'est assez cool.
C'est le cas dans calculatrice que vous avez implémentée dans un chapitre antérieur.
Vous trouverez dans le dépliant ci-dessous un exemple du code d'une telle calculatrice :
Code d'une calculatrice
# on définit les opérations
def addition(a, b) :
return a + b
def soustraction(a, b):
return a - b
def multiplication(a, b):
return a * b
# on prends les nombres en entrée
a = int(input("entrez le premier nombre: "))
op = input("entrez l'opération (+ - *) à effectuer: ")
# On vérifie que l'opération existe, sinon on redemande
while not (op == "+" or op == "-" or op == "*"):
op = input("L'opération doit être + - ou *: ")
b = int(input("entrez le second nombre: "))
#on fait le calcul
res = 0
if op == "+":
res = addition(a, b)
elif op == "-":
res = soustraction(a, b)
elif op == "*"
res = multiplication(a, b)
else :
print("ERREUR : opération", op, "inconnue !")
#on affiche le résultat
print("résultat:", res)
Activité : vérif
Copiez-collez le code ci dessus dans un fichier et vérifiez qu'il marche. Si besoin, corrigez-le.
Activité : puissance
En Python, l'opérateur puissance \(n^m\) est n ** m.
Ajoutez l'opération puissance dans le code.
def addition(a, b) :
return a + b
def soustraction(a, b):
return a - b
def multiplication(a, b):
return a * b
def puissance(a, b): #fonction
return a ** b
a = int(input("entrez le premier nombre: "))
op = input("entrez l'opération (+ - * **) à effectuer: ") #on modifie la chaine
while not (op == "+" or op == "-" or op == "*" or op == "**"): #on ajoute une conditioin
op = input("L'opération doit être + - * ou **: ") #on modifie la chaine
b = int(input("entrez le second nombre: "))
res = 0
if op == "+":
res = addition(a, b)
elif op == "-":
res = soustraction(a, b)
elif op == "*":
res = multiplication(a, b)
elif op =="**": #on ajoue un elif
res = puissance(a, b)
else :
print("ERREUR : opération", op, "inconnue !")
print("résultat:", res)
Activité : rétrospection
Comptez combien de lighes dans le code vous avez édité le code pour ajouter la puissance.
def addition(a, b) :
return a + b
def soustraction(a, b):
return a - b
def multiplication(a, b):
return a * b
def puissance(a, b): #1
return a ** b #2
a = int(input("entrez le premier nombre: "))
op = input("entrez l'opération (+ - * **) à effectuer: ") #3
while not (op == "+" or op == "-" or op == "*" or op == "**"): #4
op = input("L'opération doit être + - * ou **: ") #5
b = int(input("entrez le second nombre: "))
res = 0
if op == "+":
res = addition(a, b)
elif op == "-":
res = soustraction(a, b)
elif op == "*":
res = multiplication(a, b)
elif op =="**": #6
res = puissance(a, b) #7
else :
print("ERREUR : opération", op, "inconnue !")
print("résultat:", res)
Observez la nature de ces éditions :
- Modification complexe (difficile à vérifier sans exécuter le code) : condition d'un if / while, calcul, ...
- Ajout de code
- Modification triviale (facile à vérifier à la main) : modification d'une chaîne
def addition(a, b) :
return a + b
def soustraction(a, b):
return a - b
def multiplication(a, b):
return a * b
def puissance(a, b): # ajout
return a ** b # ajout
a = int(input("entrez le premier nombre: "))
op = input("entrez l'opération (+ - * **) à effectuer: ") # modification triviale
while not (op == "+" or op == "-" or op == "*" or op == "**"): # modification complexe
op = input("L'opération doit être + - * ou **: ") # modification triviale
b = int(input("entrez le second nombre: "))
res = 0
if op == "+":
res = addition(a, b)
elif op == "-":
res = soustraction(a, b)
elif op == "*":
res = multiplication(a, b)
elif op =="**": # modification complexe (le elif modifie le comportement du if)
res = puissance(a, b) # ajout
else :
print("ERREUR : opération", op, "inconnue !")
print("résultat:", res)
Donnez au moins deux risques d'erreur qui peuvent arriver en modifiant le code de cette manière.
Confirmez-les avec votre prof
Un risque d'erreur est de "casser" le code qu'on édite dans les modifications complexes. Par exemple, en modifiant un if.
Un autre risque d'erreur est d'oublier de modifier le code à un endroit. Par exemple, d'oublier d'ajouter ** dans la liste des opérations disponibles :
On peut modifier le code pour faire en sorte qu'ajouter une opération ne demande qu'un groupe d'ajouts (écrire la fonction) et une modification triviale, et donc réduire le risque d'erreurs !
Le saviez-vous ? En python, les fonctions sont des valeurs comme les autres, on peut par exemple les stocker dans des variables !
Activité
Qu'affiche
def fois_deux(a):
return a * 2
f2 = fois_deux #remarquez, PAS DE PARENTHESES après fois_deux
res = f2(10)
print(res)
Exécutez-le pour vérifier votre réponse !
Le code stocke fois_deux dans la variable f2,
puis appelle la fonction par le biais de la variable f2 sur la valeur 10, ce qui retourne 20 et l'affiche.
On peut se servir de ça pour utiliser un dictionnaire plutôt que des if. En effet, le bloc de code :
res = 0
if op == "+":
res = addition(a, b)
elif op == "-":
res = soustraction(a, b)
elif op == "*":
res = multiplication(a, b)
elif op =="**": # modification complexe (le elif modifie le comportement du if)
res = puissance(a, b) # ajout
else :
print("ERREUR : opération", op, "inconnue !")
ASSOCIE un opérateur donné ("+", "-", "*", "**") et une opération (respectivement addition, soustraction, multiplication, puissance).
Activité : le code
Voici un début de modification du code pour utiliser un dict au lieu de ifs.
def addition(a, b) :
return a + b
def soustraction(a, b):
return a - b
def multiplication(a, b):
return a * b
def puissance(a, b): t
return a ** b
operations = {
"+" : addition,
"-" : soustraction,
"*" : multiplication,
"**" : puissance
}
# La suite n'est pas modifiée, a vous de jouer ! #
a = int(input("entrez le premier nombre: "))
op = input("entrez l'opération (+ - * **) à effectuer: ")
while not (op == "+" or op == "-" or op == "*" or op == "**"):
op = input("L'opération doit être + - * ou **: ")
b = int(input("entrez le second nombre: "))
res = 0
if op == "+":
res = addition(a, b)
elif op == "-":
res = soustraction(a, b)
elif op == "*":
res = multiplication(a, b)
elif op =="**":
res = puissance(a, b)
else :
print("ERREUR : opération", op, "inconnue !")
print("résultat:", res)
Finissez le travail !
def addition(a, b) :
return a + b
def soustraction(a, b):
return a - b
def multiplication(a, b):
return a * b
def puissance(a, b): t
return a ** b
operations = {
"+" : addition,
"-" : soustraction,
"*" : multiplication,
"**" : puissance
}
a = int(input("entrez le premier nombre: "))
op = input("entrez l'opération " + str(list(operations))) + " à effectuer: ")
while op not in operations:
op = input("L'opération doit être " + str(list[operations]) + " : ")
b = int(input("entrez le second nombre: "))
if op not in operations: #normalement, impossible
print("ERREUR : operation", op, "inconnue")
else :
res = operations[op](a, b)
print("résultat")
Activité : vérification
Ajoutez la division, et confirmez que vous avez bien eu à n'écrire qu'une fonction et à faire une modification triviale.