Devoir n°4
Dictionnaires, POO et bases de données
1h25
Cet exercice est composé de trois parties indépendantes.
On veut créer une application permettant de stocker et de traiter des informations sur des livres de science-fiction. On désire stocker les informations suivantes :
- l’identifiant du livre
(id) - le titre
(titre) - le nom de l’auteur
(auteur) - l’année de première publication
(ann_pub) - une note sur 10
(note)
Voici un extrait des informations que l’on cherche à stocker :
| Livres de science-fiction | ||||
| id | titre | auteur | ann_pub | note |
| 1 | 1984 | Orwell | 1949 | 10 |
| 2 | Dune | Herbert | 1965 | 8 |
| 14 | Fondation | Asimov | 1951 | 9 |
| 4 | Ubik | K.Dick | 1953 | 9 |
| 8 | Blade Runner | K.Dick | 1968 | 8 |
| 7 | Les Robots | Asimov | 1950 | 10 |
| 15 | Ravage | Barjavel | 1943 | 6 |
| 17 | Chroniques martiennes | Bradbury | 1950 | 7 |
| 9 | Dragon déchu | Hamilton | 2003 | 8 |
| 10 | Fahrenheit 451 | Bradbury | 1953 | 8 |
Partie A
Dans cette première partie, on utilise un dictionnaire Python. On considère le programme suivant :
dico_livres = {
'id' : [1, 2, 14, 4, 5, 8, 7, 15, 9, 10],
'titre' : ['1984', 'Dune', 'Fondation', 'Ubik', 'Blade Runner',
'Les Robots', 'Ravage', 'Chroniques martiennes',
'Dragon déchu', 'Fahrenheit 451'],
'auteur' : ['Orwell', 'Herbert', 'Asimov', 'K.Dick', 'K.Dick', 'Asimov',
'Barjavel', 'Bradbury', 'Hamilton', 'Bradbury'],
'ann_pub' : [1949, 1965, 1951, 1953,1968, 1950, 1943, 1950, 2003, 1953],
'note' : [10, 8, 9, 9, 8, 10, 6, 7, 8, 8]
}
a = dico_livres['note']
b = dico_livres['titre'][2]
1. Déterminer les valeurs des variables a et b après l’exécution de ce programme.
La fonction titre_livre prend en paramètre un dictionnaire (de même structure que dico_livres) et un identifiant, et renvoie le titre du livre qui correspond à cet identifiant. Dans le cas où l’identifiant passé en paramètre n’est pas présent dans le dictionnaire, la fonction renvoie None.
def titre_livre(dico, id_livre):
for i in range(len(dico['id'])):
if dico['id'][i] == ... :
return dico['titre'][...]
return ...
2. Recopier et compléter les lignes 3, 4 et 5 de la fonction titre_livre.
3. Écrire une fonction note_maxi qui prend en paramètre un dictionnaire dico (de même structure que dico_livres) et qui renvoie la note maximale.
4. Écrire une fonction livres_note qui prend en paramètre un dictionnaire dico (de même structure que dico_livres) et une note n, et qui renvoie la liste des titres des livres ayant obtenu la note n (on rappelle que t.append(a) permet de rajouter l’élément a à la fin de la liste t).
5. Écrire une fonction livre_note_maxi qui prend en paramètre un dictionnaire dico (de même structure que dico_livres) et qui renvoie la liste des titres des livres ayant obtenu la meilleure note sous la forme d’une liste Python.
Partie B
Dans cette partie, on utilise le paradigme orientée objet (POO). On propose deux classes : Livre et Bibliotheque.
class Livre:
def __init__(self, id_livre, titre, auteur, ann_pub, note):
self.id = id_livre
self.titre = titre
self.auteur = auteur
self.ann_pub = ann_pub
self.note = note
def get_id(self):
return self.id
def get_titre(self):
return self.titre
def get_auteur(self):
return self.auteur
def get_ann_pub(self):
return self.ann_pub
class Bibliotheque:
def __init__(self):
self.liste_livre = []
def ajout_livre(self, livre):
self.liste_livre.append(livre)
def titre_livre(self, id_livre):
for livre in self.liste_livre :
if ... == id_livre :
return ...
return ...
6. Citer un attribut et une méthode de la classe Livre.
7. Écrire la méthode get_note de la classe Livre. Cette méthode devra renvoyer la note d’un livre.
8. Écrire le programme permettant d’ajouter le livre Blade Runner à la fin de la « bibliothèque » en utilisant la classe Livre et la classe Bibliotheque (voir le tableau en début d’exercice).
9. Recopier et compléter la méthode titre_livre de la classe Bibliotheque. Cette méthode prend en paramètre l’identifiant d’un livre et renvoie le titre du livre si l’identifiant existe, ou None si l’identifiant n’existe pas.
Partie C.
On utilise maintenant une base de données relationnelle. Les commandes nécessaires ont été exécutées afin de créer une table livres. Cette table livres contient toutes les données sur les livres. On obtient donc la table suivante :
| livres | ||||
| id | titre | auteur | ann_pub | note |
| 1 | 1984 | Orwell | 1949 | 10 |
| 2 | Dune | Herbert | 1965 | 8 |
| 14 | Fondation | Asimov | 1951 | 9 |
| 4 | Ubik | K.Dick | 1953 | 9 |
| 8 | Blade Runner | K.Dick | 1968 | 8 |
| 7 | Les Robots | Asimov | 1950 | 10 |
| 15 | Ravage | Barjavel | 1943 | 6 |
| 17 | Chroniques martiennes | Bradbury | 1950 | 7 |
| 9 | Dragon déchu | Hamilton | 2003 | 8 |
| 10 | Fahrenheit 451 | Bradbury | 1953 | 8 |
L’attribut id est la clé primaire pour la table livres.
10. Expliquer pourquoi l’attribut auteur ne peut pas être choisi comme clé primaire.
11. Donner le résultat renvoyé par la requête SQL suivante :
SELECT titre FROM livres WHERE auteur = 'K.Dick';
12. Écrire une requête SQL permettant d’obtenir les titres des livres écrits par Asimov publiés après 1950.
13. Écrire une requête SQL permettant de modifier la note du livre Ubik en la passant de 9/10 à 10/10.
On souhaite proposer plus d’informations sur les auteurs des livres. Pour cela, on crée une seconde table auteurs avec les attributs suivants :
idde type INT ;nomde type TEXT ;prenomde type TEXT ;annee_naissancede type INT (année de naissance).
| auteurs | |||
| id | nom | prenom | annee_naissance |
| 1 | Orwell | George | 1903 |
| 2 | Herbert | Franck | 1920 |
| 3 | Asimov | Isaac | 1920 |
| 4 | K.Dick | Philip | 1928 |
| 5 | Bradbury | Ray | 1920 |
| 6 | Barjavel | René | 1911 |
| 7 | Hamilton | Peter | 1960 |
La table livres est aussi modifiée comme suit :
| livres | ||||
| id | titre | id_auteur | ann_pub | note |
| 1 | 1984 | 1 | 1949 | 10 |
| 2 | Dune | 2 | 1965 | 8 |
| 14 | Fondation | 3 | 1951 | 9 |
| 4 | Ubik | 4 | 1953 | 9 |
| 8 | Blade Runner | 4 | 1968 | 8 |
| 7 | Les Robots | 3 | 1950 | 10 |
| 15 | Ravage | 6 | 1943 | 6 |
| 17 | Chroniques martiennes | 5 | 1950 | 7 |
| 9 | Dragon déchu | 7 | 2003 | 8 |
| 10 | Fahrenheit 451 | 5 | 1953 | 8 |
14. Expliquer l’intérêt d’utiliser deux tables (livres et auteurs) au lieu de regrouper toutes les informations dans une seule table.
15. Expliquer le rôle de l’attribut id_auteur de la table livres.
16. Écrire une requête SQL qui renvoie le nom et le prénom des auteurs des livres publiés après 1960.
17. Décrire par une phrase en français le résultat de la requête SQL suivante :
SELECT titre
FROM livres
JOIN auteurs ON id_auteur = auteurs.id
WHERE ann_pub - annee_naissance < 30;
Un élève décide de créer une application d’annuaire pour sa classe. On pourra retrouver, grâce à cette application, différentes informations sur les élèves de la classe : nom, prénom, date de naissance, numéro de téléphone, adresse email, etc.
18. Expliquer en quoi la réalisation de ce projet pourrait être problématique.
Correction
Partie A
1. a = [10, 8, 9, 9, 8, 10, 6, 7, 8, 8] et b = 'Fondation'.
Remarque : utiliser un dictionnaire de cette manière est totalement absurde et contre-intuitive. Il aurait été beaucoup plus logique d’avoir une liste de livres qui, eux, aurait été des dictionnaires. 🙄
B si Dune au lieu de Foundation
2. Fonction titre_livres :
# lignes à compléter
if dico['id'][i] == id_livre:
return dico['titre'][i]
return None
B si return dico['titre'][id_livre] au lieu de return dico['titre'][i]
3. Fonction note_maxi :
def note_maxi(dico):
note_maxi = 0
for n in dico['note']:
if n > note_maxi:
note_maxi = n
return note_maxi
# ou beaucoup plus court 🤓
def note_maxi(dico):
return max(dico['notes'])
4. Fonction livres_note
def livres_notes(dico, n):
livres = []
for i in range(len(dico['notes'])):
if dico['note'][i] == n : livres.append(dico['titre'][i])
return livres
25 % pour initialisation tableau vide
50 % pour boucle cohérente (for i in range(len(dico)))
20 % pour le append correct
5. Fonction livre_note_maxi
def livre_note_maxi(dico):
note_maxi = note_maxi(dico)
livres = livres_notes(dico, note_maxi)
return livres
Partie B
6. Un seul exemple est attendu dans chaque cas.
- attributs :
id,titre,auteur,ann_pub,note - methode :
get_id,get_titre,get_auteur,get_ann_pub
7. Méthode get_note
# à placer à l’intérieur de la classe
def get_note(self):
return self.note
8. Ajout d’un livre à une bibliothèque. On suppose que la bibliothèque a déjà été créée (variable bibal)
bladerunner = Livre(8, "Blade Runner", "K.Dick", 1968, 8)
bibal.ajout_livre(bladerunner)
9. Méthode titre_livre
def titre_livre(self, id_livre):
for livre in self.liste_livre :
if livre.id == id_livre :
return livre.titre
return None
25 % pour livre in self.liste_livre
Partie C
10. Parce qu’un même auteur peut être associé à plusieurs livres, et une clé primaire doit être unique.
11. Résultat requête SQL
Ubik
Blade Runner
12. Requête SQL
SELECT titre FROM livres WHERE auteur = 'Asimov' AND ann_pub > 1950;
C si WHERE à la place du AND
13. Requête SQL type UPDATE
UPDATE livres SET note = 10 WHERE titre = 'Ubik';
D si seule la clause WHERE est correcte
14. Évite la redondance des données.
0 si l’idée d’éviter la redondance des données est absente.
15. Il s’agit d’une clé étrangère permettant de lier un livre à un auteur.
D si « clé étrangère » sans autre explication
16. Requête SQL avec JOIN
SELECT auteurs.nom, auteurs.prenom
FROM auteurs
JOIN livres ON livres.id_auteur = auteurs.id
WHERE livres.ann_pub > 1960;
-25 % si ambigüité sur origine des attributs (id est à la fois dans auteurs et dans livres)
17. Titre des livres écrits avant les 30 ans de l’auteur.
18. Le recueil de données personnelles est encadré par la loi (RGPD).