# YOUR CODE HERE
= {"nom":"Margaret Costa-Royer", "tel":"08 06 18 37 28", "rue":"93, avenue Bruneau", "code":13749, "ville":"Perrot"} contact
T.P. Dictionnaires
NSI Terminale
Rappels sur les dictionnaires
Dans cette partie, nous allons fabriquer un carnet d’adresse pour stocker des contacts.
Fabrication d’un contact
Chaque contact sera un dictionnaire dont les clés seront : - nom
: Nom et prénom du contact - tel
: N° de téléphone - rue
: adresse complète - code
: code postal - ville
: ville
Créez un dictionnaire nommé contact
correspondant au contact suivant : > Margaret Costa-Royer
> 08 06 18 37 28
> 93, avenue Bruneau
> 13749 Perrot
# Vérification
assert contact["nom"] == "Margaret Costa-Royer"
assert contact["tel"] == "08 06 18 37 28"
assert contact["ville"] == "Perrot"
Ajouter une nouvelle entrée “passwd” dans le contact ayant pour valeur ‘s75JWikE&o’
# YOUR CODE HERE
"passwd"] = "s75JWikE&o" contact[
# Vérification
assert contact["passwd"] == 's75JWikE&o'
Génération automatique d’un contact
Écrire une fonction genere_contact()
- qui ne prend aucun paramètre - qui renvoie un dictionnaire possédant les mêmes clés que le contact ci-dessus, y compris “passwd”
On pourra utiliser le module faker
de python dont un exemple d’utilisation est donné dans la cellule ci-dessous.
%pip install faker
from faker import Faker
= Faker("fr_FR") # Générateur de données personnelles pour un français
fake
print(fake.name())
print(fake.phone_number())
print(fake.street_address())
print(fake.postcode(), fake.city())
print(fake.password())
Hugues Monnier de Roger
+33 (0)3 71 66 66 71
866, boulevard de Texier
82052 PhilippeBourg
dy3Ixvj)^V
Remarque : Si la cellule ci-dessus provoque une erreur disant que le module faker
n’est pas disponible, vous pouvez l’installer dans l’environnement jupyter via la commande
!pip install faker
def genere_contact():
"""Fabrique un contact factice et renvoie le contact sous forme d'un dictionnaire"""
# YOUR CODE HERE
= Faker("fr_FR")
fake = {}
contact "nom"] = fake.name()
contact["tel"] = fake.phone_number()
contact["rue"] = fake.street_address()
contact["code"] = fake.postcode()
contact["ville"] = fake.city()
contact["passwd"] = fake.password()
contact[return contact
= genere_contact()
contact1 assert type(contact1["nom"]) == str
assert "ville" in contact1
Mise en pratique
Fabrication du carnet d’adresse
Tout est à présent en place pour que nous puissions fabriquer notre carnet d’adresse.
Première implémentation
Dans une première approche, nous allons considérer que le carnet d’adresse sera une liste de contacts, chaque contact étant un dictionnaire dont la structure a été définie à la section précédente.
Fabriquez une fonction genere_carnet1
- prenant en paramètre le nombre n
de contacts à générer - renvoyant une liste de n
contacts générés aléatoirement.
def genere_carnet1(n):
"""Renvoie une liste de n contacts aléatoires"""
# YOUR CODE HERE
= []
liste for k in range(n):
liste.append(genere_contact())return liste
# vérification
= genere_carnet1(10)
carnet1 assert type(carnet1) == list
assert "nom" in carnet1[3]
Ecrire à présent une fonction est_present
- prenant 2 paramètres : un nom et un carnet d’adresse - renvoyant True
si le nom figure dans le carnet d’adresse, False
sinon
def est_present(nom, carnet):
"""Teste si nom est présent dans le carnet d'adresse"""
# YOUR CODE HERE
for contact in carnet:
if contact["nom"] == nom:
return True
return False
# Vérification
= genere_carnet1(10)
carnet1 = carnet1[-1]["nom"]
nom assert est_present(nom, carnet1)
assert not est_present("Géo Trouvetout", carnet1)
Mesure de performance de la recherche
Nous allons regarder ici comment évolue la vitesse de recherche en fonction de la taille du carnet d’adresse. On utilisera pour cela la fonction magique de jupyter : %%timeit
. Étudiez la cellule suivante :
# Fabrication d'un carnet de 100 contacts
= genere_carnet1(100)
carnet1 = carnet1[-1]["nom"] # On récupère un nom du carnet
nom nom
'Roger Joseph-Charrier'
%%timeit
# On mesure le temps d'une recherche
est_present(nom, carnet1)
2.88 µs ± 14.8 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
Vous lisez sous la cellule le temps de recherche.
A présent, on refait l’expérience pour 1000 contacts dans le carnet d’adresse.
= genere_carnet1(1000)
carnet1 = carnet1[-1]["nom"] # On récupère un nom du carnet
nom nom
'Benoît Mahe'
%%timeit
# On mesure le temps d'une recherche dans ce carnet
est_present(nom, carnet1)
33.9 µs ± 362 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
Seconde implémentation
Vous devez avoir constaté ci-dessus que le temps de recherche est proportionnel à la taille du carnet d’adresse : si celui-ci contient 10 fois plus de contact, la recherche peut être jusqu’à 10 fois plus longue.
Nous allons changer d’approche et fabriquer un carnet d’adresse sous forme d’un dictionnaire dont les clés seront les noms et les valeurs seront les fiches contacts. Ainsi notre carnet d’adresse sera un dictionnaire dont les valeurs seront des dictionnaires !
Fabriquez une fonction genere_carnet2
- prenant en paramètre le nombre n de contacts à générer - renvoyant un dictionnaire de n
contacts générés aléatoirement
def genere_carnet2(n):
"""Renvoie un dictionnaire de n contacts aléatoires"""
# YOUR CODE HERE
= {}
dico for k in range(n):
= genere_contact()
contact = contact["nom"]
nom = contact
dico[nom] return dico
# Vérification
= genere_carnet2(10)
carnet2 assert type(carnet2) == dict
= list(carnet2.keys())[-1]
nom assert type(carnet2[nom]) == dict
Mesure de performance de la recherche
Nous allons regarder pour cette nouvelle implémentation comment évolue la vitesse de recherche en fonction de la taille du carnet d’adresse. Validez les 2 cellules suivantes.
# Fabrication d'un carnet de 100 contacts
= genere_carnet2(100)
carnet2 = list(carnet2.keys())[-1] # On récupère un nom du carnet
nom nom
'Richard Andre'
%%timeit
in carnet2 # On le recherche nom
29.2 ns ± 0.196 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
On constate déjà que la recherche est plus rapide que pour la première implémentation du carnet à l’aide d’un tableau.
Refaisons l’expérience avec 100 fois plus de contacts dans le carnet !!
# Fabrication d'un carnet de 10000 contacts
= genere_carnet2(10000)
carnet2 = list(carnet2.keys())[-1] # On récupère un nom du carnet
nom nom
'Guy Pereira de Blanc'
%%timeit
in carnet2 # On le recherche nom
30.8 ns ± 0.21 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
Conclusion
Vous le constatez d’après les expériences ci-dessus : le temps de recherche dans le dictionnaire est pratiquement indépendant du nombre d’entrées dans ce dictionnaire, car en multipliant le nombre de contacts par 100, le temps est resté pratiquement identique alors que dans le cas de la recherche dans un tableau, celui-ci est proportionnel à la longueur du tableau.
Le dictionnaire est donc une structure de données optimisée pour la recherche sur les clés.