Exercice difficile : Gérer les notes d'élèves
Bonjour,
J'aimerais avoir quelques explications
Voici ma solution pour l'exercice :
class Note:
def __init__(self, valeur=""):
self.valeur = valeur
def __repr__(self):
return f"{self.valeur} / 20"
class Notes(list):
list_note = []
def ajouter_note(self, note):
Notes.list_note.append(note)
def notes_parfaites(self):
compteur = 0
for note in Notes.list_note:
if note.valeur == 20:
compteur += 1
return compteur
def moyenne(self):
somme = 0
for note in Notes.list_note:
somme += note.valeur
return round(somme/len(Notes.list_note), 1)
valeur_notes = [12, 19, 14, 13, 9, 20, 8, 15, 4, 20, 19, 17]
notes = Notes()
for valeur_note in valeur_notes:
notes.ajouter_note(note=Note(valeur=valeur_note))
print(notes.notes_parfaites())
print(notes.moyenne())
La méthode "notes_parfaites" me retourne bien 2 et la méthode "moyenne" me retourne bien 14.2
Mais seule la moyenne est validée par l'exercice, je ne comprends pas pourquoi ma méthode "notes_parfaites" n'est pas validée.
J'ai regardé la solution de Thibault et je voudrais comprendre la différence entre ma solution et celle de Thibault.
Merci,
Romuald
Salut Romuald,
Alors c'est un problème assez sournois. C'est à cause du fait que tu as décidé de mettre ta liste en attribut de classe.
Le problème c'est que mon test unitaire a un effet cumulatif avec le tiens. Tu ajoutes des notes (dont 2 parfaites) dans ta liste list_note qui est un attribut de ta classe.
Et mon test unitaire fait la même chose. Le problème c'est que comme tu as créé un attribut de classe, toutes les valeurs qui sont ajoutées dans la liste sur une instance sont ajoutées dans toutes les instances.
Tu peux t'en rendre compte en créant 2 instances à partir de ta classe et en ajoutant une note sur une seule des instances : tu verras que la 2e instance contient également la note ajoutée sur la première instance :
n1 = Notes()
n2 = Notes()
n1.ajouter_note(note=Note(20))
print(n1.list_note) # [20 / 20]
print(n2.list_note) # [20 / 20]
Du coup le code qui est exécuté par mon test unitaire est celui-ci :
# Ton code 👇
class Note:
def __init__(self, valeur=""):
self.valeur = valeur
def __repr__(self):
return f"{self.valeur} / 20"
class Notes(list):
list_note = []
def ajouter_note(self, note):
Notes.list_note.append(note)
def notes_parfaites(self):
compteur = 0
for note in Notes.list_note:
if note.valeur == 20:
compteur += 1
return compteur
def moyenne(self):
somme = 0
for note in Notes.list_note:
somme += note.valeur
return round(somme/len(Notes.list_note), 1)
valeur_notes = [12, 19, 14, 13, 9, 20, 8, 15, 4, 20, 19, 17]
notes = Notes()
for valeur_note in valeur_notes:
notes.ajouter_note(note=Note(valeur=valeur_note))
# Le code de mon test unitaire qui est ajouté après ton code 👇
valeur_notes = [12, 19, 14, 13, 9, 20, 8, 15, 4, 20, 19, 17]
notes = Notes()
for valeur_note in valeur_notes:
notes.ajouter_note(note=Note(valeur=valeur_note))
# Ici, l'instance notes contient donc 24 valeurs (2 fois les valeurs de valeur_notes). Il y a donc 4 notes parfaites et non 2.
assert notes.notes_parfaites() == 2, "La méthode notes_parfaites ne retourne pas la bonne valeur."
J'espère que c'était suffisamment clair, problème assez sournoi mais important, car tu remarques bien la différence de définir un attribut de classe ou d'instance ! En déclarant un attribut sur la classe, il est partagé par toutes les instances que tu crées à partir de la classe. Et dans le cas d'un objet muable comme une liste, ça peut causer pas mal d'effets de bords de ce style.
Bonne continuation !
Bonsoir Thibault,
Effectivement, c'est très sournois, je me doutais bien que le problème venait de mon attribut de classe mais je ne comprenais pas pourquoi
C'est un concept assez compliqué à assimiler, si il y a une vidéo sur le sujet, j'ai dû la regarder sans vraiment comprendre comment ça fonctionnait
De plus, je n'avais pas compris qu'on pouvait utilisait le "self" directement sur l'instance comme "self.append()"
Je vais continuer à m'entrainer pour bien comprendre ce concept d'attribut de classe et d'instance.
Merci pour les explications
Inscris-toi
(c'est gratuit !)
Tu dois créer un compte pour participer aux discussions.
Créer un compte