Puisqu'il s'agit d'une réponse si populaire, j'aimerais aborder quelques sujets d'utilisation légèrement avancés.
cPickle(ou _pickle) vspickle
Il est presque toujours préférable d'utiliser réellement le cPicklemodule plutôt que pickleparce que le premier est écrit en C et est beaucoup plus rapide. Il existe quelques différences subtiles entre eux, mais dans la plupart des situations, ils sont équivalents et la version C fournira des performances considérablement supérieures. Passer à cela ne pourrait pas être plus facile, changez simplement la importdéclaration en ceci:
Le résumé est que vous pouvez utiliser quelque chose comme ce qui suit pour vous assurer que votre code utilisera toujours la version C lorsqu'elle est disponible à la fois en Python 2 et 3:
try:import cPickle as pickleexceptModuleNotFoundError:import pickle
Formats de flux de données (protocoles)
picklepeut lire et écrire des fichiers dans plusieurs formats différents, spécifiques à Python, appelés protocoles comme décrit dans la documentation , "Protocol version 0" est ASCII et donc "lisible par l'homme". Les versions> 0 sont binaires et la plus élevée disponible dépend de la version de Python utilisée. La valeur par défaut dépend également de la version de Python. Dans Python 2, la version par défaut était Protocol 0, mais dans Python 3.8.1, c'est la version Protocol 4. Dans Python 3.x, le module y avait été pickle.DEFAULT_PROTOCOLajouté, mais cela n'existe pas dans Python 2.
Heureusement, il y a un raccourci pour écrire pickle.HIGHEST_PROTOCOLdans chaque appel (en supposant que c'est ce que vous voulez, et vous le faites habituellement), utilisez simplement le numéro littéral -1- similaire à référencer le dernier élément d'une séquence via un index négatif. Donc, au lieu d'écrire:
pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)
Vous pouvez simplement écrire:
pickle.dump(obj, output,-1)
Quoi qu'il en soit, vous n'auriez à spécifier le protocole qu'une seule fois si vous avez créé un Picklerobjet à utiliser dans plusieurs opérations de décapage:
Remarque : Si vous êtes dans un environnement exécutant différentes versions de Python, vous voudrez probablement utiliser explicitement (c'est-à-dire le code dur) un numéro de protocole spécifique que tous peuvent lire (les versions ultérieures peuvent généralement lire les fichiers produits par des versions antérieures) .
Objets multiples
Alors qu'un fichier cornichon peut contenir un certain nombre d'objets marinées, comme le montrent les exemples ci - dessus, quand il y a un nombre inconnu d'entre eux, il est souvent plus facile de les stocker dans une sorte de conteneur taille variable, comme un list, tupleou dictet écriture tous dans le fichier en un seul appel:
et restaurer la liste et tout ce qu'il contient plus tard avec:
with open('tech_companies.pkl','rb')as input:
tech_companies = pickle.load(input)
L'avantage majeur est que vous n'avez pas besoin de savoir combien d'instances d'objet sont enregistrées pour les recharger plus tard (bien que cela sans ces informations soit possible, cela nécessite du code légèrement spécialisé). Voir les réponses à la question connexe Enregistrer et charger plusieurs objets dans un fichier pickle? pour plus de détails sur les différentes façons de procéder. Personnellement , je LIKE @Lutz Prechelt réponse le meilleur. Voici adapté aux exemples ici:
classCompany:def __init__(self, name, value):
self.name = name
self.value = valuedef pickled_items(filename):""" Unpickle a file of pickled data. """with open(filename,"rb")as f:whileTrue:try:yield pickle.load(f)exceptEOFError:breakprint('Companies in pickle file:')for company in pickled_items('company_data.pkl'):print(' name: {}, value: {}'.format(company.name, company.value))
C'est rare pour moi car j'imaginais qu'il y aurait un moyen plus simple de sauvegarder un objet ... Quelque chose comme 'saveobject (company1, c: \ mypythonobjects)
Peterstone
4
@Peterstone: Si vous ne vouliez stocker qu'un seul objet, vous n'auriez besoin que d'environ la moitié du code comme dans mon exemple - je l'ai délibérément écrit comme je l'ai fait pour montrer comment plus d'un objet pourrait être enregistré (et plus tard relu de) le même fichier.
martineau
1
@Peterstone, il y a une très bonne raison pour la séparation des responsabilités. De cette façon, il n'y a pas de limitation sur la façon dont les données du processus de décapage sont utilisées. Vous pouvez le stocker sur disque ou vous pouvez également l'envoyer via une connexion réseau.
Harald Scheirich
3
@martinaeau, c'était en réponse à la remarque de perstones selon laquelle il ne devrait y avoir qu'une seule fonction pour enregistrer un objet sur le disque. La responsabilité des cornichons consiste uniquement à transformer un objet en données pouvant être traitées comme un morceau. L'écriture de choses dans un fichier est la responsabilité des objets fichier. En gardant les choses séparées, on permet une réutilisation plus élevée, par exemple être en mesure d'envoyer les données décapées sur une connexion réseau ou de les stocker dans une base de données, toutes les responsabilités sont distinctes de la conversion réelle des données <-> objets
Harald Scheirich
1
Vous supprimez company1et company2. Pourquoi ne supprimez-vous pas Companyet ne montrez- vous pas ce qui se passe?
Mike McKerns
49
Je pense que c'est une hypothèse assez forte de supposer que l'objet est un class. Et si ce n'est pas un class? Il y a aussi l'hypothèse que l'objet n'a pas été défini dans l'interpréteur. Et si c'était défini dans l'interprète? Et si les attributs étaient ajoutés dynamiquement? Lorsque certains objets python ont des attributs ajoutés à leur __dict__création après, picklene respecte pas l'ajout de ces attributs (c'est-à-dire qu'il «oublie» qu'ils ont été ajoutés - car picklesérialise par référence à la définition de l'objet).
Dans tous ces cas, pickleet cPicklepeut vous échouer horriblement.
Si vous cherchez à enregistrer un objectfichier (créé arbitrairement), où vous avez des attributs (soit ajoutés dans la définition de l'objet, soit après) ... votre meilleur pari est d'utiliser dill, qui peut sérialiser presque tout en python.
Nous commençons par une classe…
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.1((tags/Apple/clang-421.11.66))] on darwinType"help","copyright","credits"or"license"for more information.>>>import pickle>>>classCompany:...pass...>>> company1 =Company()>>> company1.name ='banana'>>> company1.value =40>>>with open('company.pkl','wb')as f:... pickle.dump(company1, f, pickle.HIGHEST_PROTOCOL)...>>>
Maintenant, arrêtez et redémarrez ...
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.1((tags/Apple/clang-421.11.66))] on darwinType"help","copyright","credits"or"license"for more information.>>>import pickle>>>with open('company.pkl','rb')as f:... company1 = pickle.load(f)...Traceback(most recent call last):File"<stdin>", line 2,in<module>File"/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1378,in loadreturnUnpickler(file).load()File"/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 858,in load
dispatch[key](self)File"/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1090,in load_global
klass = self.find_class(module, name)File"/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1126,in find_class
klass = getattr(mod, name)AttributeError:'module' object has no attribute 'Company'>>>
Oups… pickleje ne peux pas le supporter. Essayons dill. Nous allons ajouter un autre type d'objet (a lambda) pour faire bonne mesure.
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.1((tags/Apple/clang-421.11.66))] on darwinType"help","copyright","credits"or"license"for more information.>>>import dill>>>with open('company_dill.pkl','rb')as f:... company1 = dill.load(f)... company2 = dill.load(f)...>>> company1 <__main__.Company instance at 0x107909128>>>> company1.name'banana'>>> company1.value40>>> company2.name'rhubarb'>>> company2.value42>>>
Ça marche. La raison pickleéchoue, et dillne le fait pas, est que dilltraite __main__comme un module (pour la plupart), et peut également décaper les définitions de classe au lieu de décaper par référence (comme le picklefait). La raison pour laquelle dillun cornichon lambdaest qu'il lui donne un nom… alors la magie du décapage peut se produire.
En fait, il existe un moyen plus simple de sauvegarder tous ces objets, surtout si vous avez créé beaucoup d'objets. Il suffit de vider toute la session python et d'y revenir plus tard.
Maintenant, éteignez votre ordinateur, allez déguster un expresso ou autre chose, et revenez plus tard ...
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.1((tags/Apple/clang-421.11.66))] on darwinType"help","copyright","credits"or"license"for more information.>>>import dill>>> dill.load_session('dill.pkl')>>> company1.name'banana'>>> company1.value40>>> company2.name'rhubarb'>>> company2.value42>>> company2<function <lambda> at 0x1065f2938>
Le seul inconvénient majeur est qu'il dillne fait pas partie de la bibliothèque standard de python. Donc, si vous ne pouvez pas installer un package python sur votre serveur, vous ne pouvez pas l'utiliser.
Cependant, si vous pouvez installer des packages python sur votre système, vous pouvez obtenir la dernière version dillavec git+https://github.com/uqfoundation/dill.git@master#egg=dill. Et vous pouvez obtenir la dernière version publiée avec pip install dill.
J'obtiens un TypeError: __new__() takes at least 2 arguments (1 given)en essayant d'utiliser dill(ce qui semble prometteur) avec un objet plutôt complexe qui inclut un fichier audio.
MikeiLL
1
@MikeiLL: Vous obtenez un TypeErrorquand vous faites quoi, exactement? C'est généralement un signe d'avoir le mauvais nombre d'arguments lors de l'instanciation d'une instance de classe. Si cela ne fait pas partie du flux de travail de la question ci-dessus, pourriez-vous la poster comme une autre question, me la soumettre par e-mail ou l'ajouter en tant que problème sur la dillpage github?
Mike McKerns
3
Pour tous ceux qui suivent, voici la question connexe publiée par @MikeLL - d'après la réponse, ce n'était apparemment pas un dillproblème.
martineau
dilJe me donne quand MemoryErrormême! il en va cPickle, pickleet hickle.
Färid Alijani
4
Vous pouvez utiliser anycache pour faire le travail à votre place. Il considère tous les détails:
Il utilise aneth comme backend, ce qui étend le picklemodule python à gérer lambdaet toutes les fonctionnalités intéressantes de python.
Il stocke différents objets dans différents fichiers et les recharge correctement.
Limite la taille du cache
Permet l'effacement du cache
Permet le partage d'objets entre plusieurs exécutions
Permet le respect des fichiers d'entrée qui influencent le résultat
En supposant que vous ayez une fonction myfuncqui crée l'instance:
from anycache import anycacheclassCompany(object):def __init__(self, name, value):
self.name = name
self.value = value@anycache(cachedir='/path/to/your/cache')def myfunc(name, value)returnCompany(name, value)
Anycache appelle myfuncla première fois et décapage le résultat dans un fichier en cachedirutilisant un identifiant unique (en fonction du nom de la fonction et de ses arguments) comme nom de fichier. Lors d'une exécution consécutive, l'objet mariné est chargé. Si le cachedirest conservé entre les exécutions python, l'objet mariné est repris de l'exécution python précédente.
Comment utiliserait-on anycachepour enregistrer plus d'une instance de, disons, un classconteneur tel qu'un list(qui n'était pas le résultat de l'appel d'une fonction)?
martineau
2
Exemple rapide à l'aide company1de votre question, avec python3.
import pickle# Save the file
pickle.dump(company1, file = open("company1.pickle","wb"))# Reload the file
company1_reloaded = pickle.load(open("company1.pickle","rb"))
Cependant, comme cette réponse l'a noté, le cornichon échoue souvent. Vous devez donc vraiment utiliser dill.
import dill# Save the file
dill.dump(company1, file = open("company1.pickle","wb"))# Reload the file
company1_reloaded = dill.load(open("company1.pickle","rb"))
protocol=pickle.HIGHEST_PROTOCOL
. Ma réponse donne également des alternatives au cornichon.Réponses:
Vous pouvez utiliser le
pickle
module dans la bibliothèque standard. En voici une application élémentaire à votre exemple:Vous pouvez également définir votre propre utilitaire simple comme le suivant qui ouvre un fichier et y écrit un seul objet:
Mettre à jour
Puisqu'il s'agit d'une réponse si populaire, j'aimerais aborder quelques sujets d'utilisation légèrement avancés.
cPickle
(ou_pickle
) vspickle
Il est presque toujours préférable d'utiliser réellement le
cPickle
module plutôt quepickle
parce que le premier est écrit en C et est beaucoup plus rapide. Il existe quelques différences subtiles entre eux, mais dans la plupart des situations, ils sont équivalents et la version C fournira des performances considérablement supérieures. Passer à cela ne pourrait pas être plus facile, changez simplement laimport
déclaration en ceci:En Python 3, a
cPickle
été renommé_pickle
, mais cela n'est plus nécessaire puisque lepickle
module le fait maintenant automatiquement - voir Quelle différence entre pickle et _pickle en python 3? .Le résumé est que vous pouvez utiliser quelque chose comme ce qui suit pour vous assurer que votre code utilisera toujours la version C lorsqu'elle est disponible à la fois en Python 2 et 3:
Formats de flux de données (protocoles)
pickle
peut lire et écrire des fichiers dans plusieurs formats différents, spécifiques à Python, appelés protocoles comme décrit dans la documentation , "Protocol version 0" est ASCII et donc "lisible par l'homme". Les versions> 0 sont binaires et la plus élevée disponible dépend de la version de Python utilisée. La valeur par défaut dépend également de la version de Python. Dans Python 2, la version par défaut était Protocol0
, mais dans Python 3.8.1, c'est la version Protocol4
. Dans Python 3.x, le module y avait étépickle.DEFAULT_PROTOCOL
ajouté, mais cela n'existe pas dans Python 2.Heureusement, il y a un raccourci pour écrire
pickle.HIGHEST_PROTOCOL
dans chaque appel (en supposant que c'est ce que vous voulez, et vous le faites habituellement), utilisez simplement le numéro littéral-1
- similaire à référencer le dernier élément d'une séquence via un index négatif. Donc, au lieu d'écrire:Vous pouvez simplement écrire:
Quoi qu'il en soit, vous n'auriez à spécifier le protocole qu'une seule fois si vous avez créé un
Pickler
objet à utiliser dans plusieurs opérations de décapage:Remarque : Si vous êtes dans un environnement exécutant différentes versions de Python, vous voudrez probablement utiliser explicitement (c'est-à-dire le code dur) un numéro de protocole spécifique que tous peuvent lire (les versions ultérieures peuvent généralement lire les fichiers produits par des versions antérieures) .
Objets multiples
Alors qu'un fichier cornichon peut contenir un certain nombre d'objets marinées, comme le montrent les exemples ci - dessus, quand il y a un nombre inconnu d'entre eux, il est souvent plus facile de les stocker dans une sorte de conteneur taille variable, comme un
list
,tuple
oudict
et écriture tous dans le fichier en un seul appel:et restaurer la liste et tout ce qu'il contient plus tard avec:
L'avantage majeur est que vous n'avez pas besoin de savoir combien d'instances d'objet sont enregistrées pour les recharger plus tard (bien que cela sans ces informations soit possible, cela nécessite du code légèrement spécialisé). Voir les réponses à la question connexe Enregistrer et charger plusieurs objets dans un fichier pickle? pour plus de détails sur les différentes façons de procéder. Personnellement , je LIKE @Lutz Prechelt réponse le meilleur. Voici adapté aux exemples ici:
la source
company1
etcompany2
. Pourquoi ne supprimez-vous pasCompany
et ne montrez- vous pas ce qui se passe?Je pense que c'est une hypothèse assez forte de supposer que l'objet est un
class
. Et si ce n'est pas unclass
? Il y a aussi l'hypothèse que l'objet n'a pas été défini dans l'interpréteur. Et si c'était défini dans l'interprète? Et si les attributs étaient ajoutés dynamiquement? Lorsque certains objets python ont des attributs ajoutés à leur__dict__
création après,pickle
ne respecte pas l'ajout de ces attributs (c'est-à-dire qu'il «oublie» qu'ils ont été ajoutés - carpickle
sérialise par référence à la définition de l'objet).Dans tous ces cas,
pickle
etcPickle
peut vous échouer horriblement.Si vous cherchez à enregistrer un
object
fichier (créé arbitrairement), où vous avez des attributs (soit ajoutés dans la définition de l'objet, soit après) ... votre meilleur pari est d'utiliserdill
, qui peut sérialiser presque tout en python.Nous commençons par une classe…
Maintenant, arrêtez et redémarrez ...
Oups…
pickle
je ne peux pas le supporter. Essayonsdill
. Nous allons ajouter un autre type d'objet (alambda
) pour faire bonne mesure.Et maintenant, lisez le fichier.
Ça marche. La raison
pickle
échoue, etdill
ne le fait pas, est quedill
traite__main__
comme un module (pour la plupart), et peut également décaper les définitions de classe au lieu de décaper par référence (comme lepickle
fait). La raison pour laquelledill
un cornichonlambda
est qu'il lui donne un nom… alors la magie du décapage peut se produire.En fait, il existe un moyen plus simple de sauvegarder tous ces objets, surtout si vous avez créé beaucoup d'objets. Il suffit de vider toute la session python et d'y revenir plus tard.
Maintenant, éteignez votre ordinateur, allez déguster un expresso ou autre chose, et revenez plus tard ...
Le seul inconvénient majeur est qu'il
dill
ne fait pas partie de la bibliothèque standard de python. Donc, si vous ne pouvez pas installer un package python sur votre serveur, vous ne pouvez pas l'utiliser.Cependant, si vous pouvez installer des packages python sur votre système, vous pouvez obtenir la dernière version
dill
avecgit+https://github.com/uqfoundation/dill.git@master#egg=dill
. Et vous pouvez obtenir la dernière version publiée avecpip install dill
.la source
TypeError: __new__() takes at least 2 arguments (1 given)
en essayant d'utiliserdill
(ce qui semble prometteur) avec un objet plutôt complexe qui inclut un fichier audio.TypeError
quand vous faites quoi, exactement? C'est généralement un signe d'avoir le mauvais nombre d'arguments lors de l'instanciation d'une instance de classe. Si cela ne fait pas partie du flux de travail de la question ci-dessus, pourriez-vous la poster comme une autre question, me la soumettre par e-mail ou l'ajouter en tant que problème sur ladill
page github?dill
problème.dil
Je me donne quandMemoryError
même! il en vacPickle
,pickle
ethickle
.Vous pouvez utiliser anycache pour faire le travail à votre place. Il considère tous les détails:
pickle
module python à gérerlambda
et toutes les fonctionnalités intéressantes de python.En supposant que vous ayez une fonction
myfunc
qui crée l'instance:Anycache appelle
myfunc
la première fois et décapage le résultat dans un fichier encachedir
utilisant un identifiant unique (en fonction du nom de la fonction et de ses arguments) comme nom de fichier. Lors d'une exécution consécutive, l'objet mariné est chargé. Si lecachedir
est conservé entre les exécutions python, l'objet mariné est repris de l'exécution python précédente.Pour plus de détails voir la documentation
la source
anycache
pour enregistrer plus d'une instance de, disons, unclass
conteneur tel qu'unlist
(qui n'était pas le résultat de l'appel d'une fonction)?Exemple rapide à l'aide
company1
de votre question, avec python3.Cependant, comme cette réponse l'a noté, le cornichon échoue souvent. Vous devez donc vraiment utiliser
dill
.la source