Résolue

Exercice difficile : Gérer les notes d'élèves

# Orienté objet # Exercices # Correction de code

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

Thibault houdon

Mentor

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 !)

Inscris-toi

Tu dois créer un compte pour participer aux discussions.

Créer un compte

Rechercher sur le site

Formulaire de contact

Inscris-toi à Docstring

Pour commencer ton apprentissage.

Tu as déjà un compte ? Connecte-toi.