Bonjour, je débute complètement en programmation, je suis le tutoriel "Apprenez à programmer en Python" de Vincent Le Goff (très bien fait en passant) et j'ai un petit problème. Je suis arrivé à la fin du chapitre sur les méthodes spéciales, à propos des méthodes __getstate__ et __setstate__ permettant de définir comment un objet est enregistré avec pickle.
Voici un extrait du tutoriel afin que vous puissiez voir clairement de quoi il s'agit :
"On crée une classe qui va contenir plusieurs attributs. Un de ces attributs possède une valeur temporaire, qui n'est utile que pendant l'exécution du programme. Si on arrête ce programme et qu'on le relance, on doit récupérer le même objet mais la valeur temporaire doit être remise à0, par exemple."
Elle enregistre le dictionnaire des attributs dans une variable locale 'dict_attr'. Ce dictionnaire a le même contenu que 'self.__dict__'. En revanche, il a une référence différente. Sans cela, à la ligne suivante, au moment de modifier 'attribut_temporaire', le changement aurait été également appliqué à l'objet, ce que l'on veut éviter.
Je définis ensuite une fonction sauvegarder et une fonction charger :
def sauvegarder(self):
with open("sauvegarde","wb") as file :
pickler = pickle.Pickler(file)
pickler.dump(self)
def charger():
with open("sauvegarde","rb") as file :
unpickler = pickle.Unpickler(file)
objet_recup = unpickler.load()
return objet_recup
C'est là que mon problème apparaît :
J'exécute le code dans l'interpréteur. Je crée dans l'interpréteur un objet de la classe Temp (objet = Temp()). J'exécute la fonction sauvegarder (sauvegarder(objet)).
Pour la fonction sauvegarder, cela fonctionne parfaitement, la méthode __getstate__ est bien appelée au moment de l'enregistrement, la ligne print("getstate works") est exécutée.
C'est au moment de charger l'objet que je suis un peu perdu. Comme je l'ai dit précédemment, je suis totalement novice dans le domaine, j'ai donc encore du mal à appréhender ce genre de mécanismes. Je ne sais pas comment m'y prendre pour charger le fichier, qui est censé me renvoyer le même objet avec l'attribut_temporaire à 0 au lieu de 5.
Lorsque j'exécute directement la fonction charger() dans l'interpréteur juste après avoir sauvegardé, la fonction est exécutée, il n'y a pas de message d'erreur mais si j'entre ensuite "objet_recup.attribut_temporaire", l'erreur suivante apparaît :
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
objet_recup.attribut_temporaire
NameError: name 'objet_recup' is not defined
Le code de la fonction charger(self) n'est qu'une version parmi toutes celles que j'ai essayées, je suis dessus depuis hier et je n'arrive pas à trouver de solution. J'ai testé différentes choses, mais toujours à l'aveugle car comme je l'ai dit, je ne comprend pas réellement ce que je fais. D'après le tutoriel :
"Si vous tentez d'enregistrer cet objet grâce à 'pickle' et que vous le récupérez ensuite depuis le fichier, vous constatez que l'attribut 'attribut_temporaire' est à 0, peu importe sa valeur d'origine".
Or dans les autres solutions que j'ai essayées, où la fonction charger() renvoyait directement unpickler.load par exemple, sans créer de nouvelle variable 'objet_recup', objet.attribut_temporaire me renvoyait toujours '5'.
Lorsque, au lieu d'exécuter directement charger() après sauvegarder() dans le même interpréteur, je quitte l'idle pour ouvrir une nouvelle session et que j'importe le module, au moment de charger() j'ai le message d'erreur suivant :
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
objet
NameError: name 'objet' is not defined
La liste n'est pas exhaustive, je pense que le post est suffisamment long comme ça, j'ai essayé beaucoup de choses et certaines dont je ne me rappelle même pas. J'espère que ce n'est pas trop confus.
Ce que j'aimerais, s'il vous plaît, c'est donc que quelqu'un puisse m'indiquer, premièrement, l'erreur que je commets (je ne comprends pas ce qui m'échappe), et deuxièmement, la marche à suivre pour obtenir ce que je veux, à savoir charger le fichier "sauvegarde" et récupérer l'objet créé avec l'attribut_temporaire modifié. Dans l'idéal avec assez d'explications pour que je puisse bien comprendre ce que je fais et ce qu'il se passe, et si quelqu'un avait par hasard le temps et l'amabilité de m'éclairer un peu sur le fonctionnement de pickle, je lui en serai infiniment reconnaissant parce que même si le tutoriel est explicite, je pense qu'une explication différente ne me ferait pas de mal.
Voilà, j'espère que ce n'est pas trop confus et que j'ai été suffisamment exhaustif parce que j'ai beaucoup bidouillé, excusez moi aussi si je n'ai pas respecté certaines conventions mais c'est la première fois que je poste un message sur un forum.
Merci d'avance.
EDIT:
Ok alors j'ai finalement réussi à trouver la solution. Au cas où un autre débutant serait confronté à un problème similaire : en fait il se trouve qu'il manquait simplement un underscore à la ligne dict_attr["attribut temporaire"] = 0
Maintenant la valeur renvoyée est la bonne et pour le message d'erreur :
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
objet_recup.attribut_temporaire
NameError: name 'objet_recup' is not defined
J'ai découvert que c'était dû au fait que la variable est définie dans le corps de la fonction, qui est détruit immédiatement après l'exécution. Il suffisait de rajouter après la définition de la fonction objet_recup = charger().
Content que tu aies trouvé la solution à ton problème.
En tout cas chapeau pour ce sujet qui explique vraiment bien et en détails le soucis rencontré, ce n'est pas tous les jours qu'on lit un sujet comme ça !
Merci, faut croire que je suis meilleur en rédaction qu'en programmation, quand je pense au temps que j'ai passé là dessus juste pour underscore oublié !
Merci, faut croire que je suis meilleur en rédaction qu'en programmation, quand je pense au temps que j'ai passé là dessus juste pour underscore oublié !
Bonjour Nicolas,
Meilleur voeux pour 2019!
Je fais le meme constat que toi, j'y passe un temps de fou sur ce cours.. Ca t'a apporté, jespere?
Moi je suis aussi bloqué sur ce sujet! Je vais créer un nouveau sujet ca rle load ne me retourne pas ce que j'attends :-(
Jérôme Bonneval
Sérialiser une instance de classe via __getstate__
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
entwanne — @entwanne — Un zeste de Python — La POO en Python — Notions de Python avancées — Les secrets d'un code pythonique
Jérôme Bonneval