Ho creato un oggetto come questo:
company1.name = 'banana'
company1.value = 40
Vorrei salvare questo oggetto. Come lo posso fare?
protocol=pickle.HIGHEST_PROTOCOL. La mia risposta offre anche alternative al sottaceto.
Ho creato un oggetto come questo:
company1.name = 'banana'
company1.value = 40
Vorrei salvare questo oggetto. Come lo posso fare?
protocol=pickle.HIGHEST_PROTOCOL. La mia risposta offre anche alternative al sottaceto.
Risposte:
È possibile utilizzare il picklemodulo nella libreria standard. Ecco una sua elementare applicazione al tuo esempio:
import pickle
class Company(object):
def __init__(self, name, value):
self.name = name
self.value = value
with open('company_data.pkl', 'wb') as output:
company1 = Company('banana', 40)
pickle.dump(company1, output, pickle.HIGHEST_PROTOCOL)
company2 = Company('spam', 42)
pickle.dump(company2, output, pickle.HIGHEST_PROTOCOL)
del company1
del company2
with open('company_data.pkl', 'rb') as input:
company1 = pickle.load(input)
print(company1.name) # -> banana
print(company1.value) # -> 40
company2 = pickle.load(input)
print(company2.name) # -> spam
print(company2.value) # -> 42
Puoi anche definire la tua semplice utility come la seguente che apre un file e scrive un singolo oggetto su di esso:
def save_object(obj, filename):
with open(filename, 'wb') as output: # Overwrites any existing file.
pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)
# sample usage
save_object(company1, 'company1.pkl')
Dal momento che questa è una risposta così popolare, vorrei toccare alcuni argomenti di utilizzo leggermente avanzati.
cPickle(o _pickle) vspickleÈ quasi sempre preferibile utilizzare effettivamente il cPicklemodulo piuttosto che pickleperché il primo è scritto in C ed è molto più veloce. Ci sono alcune sottili differenze tra loro, ma nella maggior parte delle situazioni sono equivalenti e la versione C fornirà prestazioni notevolmente superiori. Passare ad esso non potrebbe essere più semplice, basta cambiare l' importistruzione in questo:
import cPickle as pickle
In Python 3, è cPicklestato rinominato _pickle, ma farlo non è più necessario poiché il picklemodulo ora lo fa automaticamente: vedi Che differenza tra pickle e _pickle in python 3? .
Il riassunto è che potresti usare qualcosa di simile al seguente per assicurarti che il tuo codice userà sempre la versione C quando è disponibile in Python 2 e 3:
try:
import cPickle as pickle
except ModuleNotFoundError:
import pickle
picklepuò leggere e scrivere file in diversi formati specifici di Python, chiamati protocolli come descritto nella documentazione , "Protocollo versione 0" è ASCII e quindi "leggibile dall'uomo". Le versioni> 0 sono binarie e la più alta disponibile dipende dalla versione di Python utilizzata. L'impostazione predefinita dipende anche dalla versione di Python. In Python 2 l'impostazione predefinita era Versione protocollo 0, ma in Python 3.8.1 è la versione Protocollo 4. In Python 3.x al modulo è stato pickle.DEFAULT_PROTOCOLaggiunto un modulo , ma ciò non esiste in Python 2.
Fortunatamente c'è una scorciatoia per scrivere pickle.HIGHEST_PROTOCOLin ogni chiamata (supponendo che sia quello che vuoi, e di solito lo fai), basta usare il numero letterale -1- simile a fare riferimento all'ultimo elemento di una sequenza tramite un indice negativo. Quindi, invece di scrivere:
pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)
Puoi semplicemente scrivere:
pickle.dump(obj, output, -1)
In entrambi i casi, avresti specificato il protocollo una sola volta se avessi creato un Pickleroggetto da utilizzare in più operazioni di pickle:
pickler = pickle.Pickler(output, -1)
pickler.dump(obj1)
pickler.dump(obj2)
etc...
Nota : se ti trovi in un ambiente con versioni diverse di Python, probabilmente vorrai utilizzare esplicitamente (ad esempio un hardcode) un numero di protocollo specifico che tutti possono leggere (le versioni successive possono generalmente leggere i file prodotti da quelli precedenti) .
Mentre un file di salamoia può contenere qualsiasi numero di oggetti in salamoia, come mostrato nei campioni di cui sopra, quando c'è un numero imprecisato di loro, è spesso più facile per memorizzare tutti in una sorta di contenitore variabile dimensioni, come una list, tupleo dicte scrivere tutti al file in una sola chiamata:
tech_companies = [
Company('Apple', 114.18), Company('Google', 908.60), Company('Microsoft', 69.18)
]
save_object(tech_companies, 'tech_companies.pkl')
e ripristina l'elenco e tutto il resto in seguito con:
with open('tech_companies.pkl', 'rb') as input:
tech_companies = pickle.load(input)
Il vantaggio principale è che non è necessario sapere quante istanze di oggetto vengono salvate per poterle ricaricare in un secondo momento (anche se è possibile farlo senza tali informazioni , richiede un codice leggermente specializzato). Vedi le risposte alla domanda correlata Salvare e caricare più oggetti nel file pickle? per dettagli su diversi modi per farlo. Personalmente mi piace la risposta di @Lutz Prechelt al meglio. Ecco adattato agli esempi qui:
class Company:
def __init__(self, name, value):
self.name = name
self.value = value
def pickled_items(filename):
""" Unpickle a file of pickled data. """
with open(filename, "rb") as f:
while True:
try:
yield pickle.load(f)
except EOFError:
break
print('Companies in pickle file:')
for company in pickled_items('company_data.pkl'):
print(' name: {}, value: {}'.format(company.name, company.value))
company1e company2. Perché non elimini Companye mostri anche cosa succede?
Penso che sia un presupposto piuttosto forte supporre che l'oggetto sia un class. E se non fosse un class? Si presume anche che l'oggetto non sia stato definito nell'interprete. E se fosse stato definito nell'interprete? Inoltre, cosa succede se gli attributi vengono aggiunti in modo dinamico? Quando alcuni oggetti Python hanno degli attributi aggiunti alla loro __dict__creazione successiva, picklenon rispetta l'aggiunta di quegli attributi (cioè "dimentica" che sono stati aggiunti - perché pickleserializza facendo riferimento alla definizione dell'oggetto).
In tutti questi casi, picklee cPicklepuò fallirti in modo orribile.
Se stai cercando di salvare un object(creato arbitrariamente), dove hai degli attributi (o aggiunti nella definizione dell'oggetto, o in seguito) ... la tua scommessa migliore è usare dill, che può serializzare quasi tutto in Python.
Iniziamo con una lezione ...
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pickle
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>> with open('company.pkl', 'wb') as f:
... pickle.dump(company1, f, pickle.HIGHEST_PROTOCOL)
...
>>>
Ora spegni e riavvia ...
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "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 load
return Unpickler(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'
>>>
Oops ... picklenon ce la faccio. Prova di Let dill. Inseriremo un altro tipo di oggetto (a lambda) per buona misura.
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>>
>>> company2 = lambda x:x
>>> company2.name = 'rhubarb'
>>> company2.value = 42
>>>
>>> with open('company_dill.pkl', 'wb') as f:
... dill.dump(company1, f)
... dill.dump(company2, f)
...
>>>
E ora leggi il file.
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "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.value
40
>>> company2.name
'rhubarb'
>>> company2.value
42
>>>
Funziona. La ragione picklefallisce e dillnon lo fa, è che dilltratta __main__come un modulo (per la maggior parte), e può anche decapare le definizioni delle classi invece di decapitarle per riferimento (come picklefa). La ragione per cui si dillpuò mettere sottaceto a lambdaè che gli dà un nome ... quindi può succedere la magia di decapaggio.
In realtà, c'è un modo più semplice per salvare tutti questi oggetti, specialmente se hai molti oggetti che hai creato. Scarica semplicemente l'intera sessione di Python e torna più tardi.
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>>
>>> company2 = lambda x:x
>>> company2.name = 'rhubarb'
>>> company2.value = 42
>>>
>>> dill.dump_session('dill.pkl')
>>>
Ora spegni il computer, vai a goderti un espresso o altro e torna più tardi ...
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> dill.load_session('dill.pkl')
>>> company1.name
'banana'
>>> company1.value
40
>>> company2.name
'rhubarb'
>>> company2.value
42
>>> company2
<function <lambda> at 0x1065f2938>
L'unico svantaggio principale è che dillnon fa parte della libreria standard di Python. Quindi se non puoi installare un pacchetto Python sul tuo server, non puoi usarlo.
Tuttavia, se sei in grado di installare pacchetti Python sul tuo sistema, puoi ottenere le ultime novità dillcon git+https://github.com/uqfoundation/dill.git@master#egg=dill. E puoi ottenere l'ultima versione rilasciata con pip install dill.
TypeError: __new__() takes at least 2 arguments (1 given)tentativo quando uso dill(che sembra promettente) con un oggetto piuttosto complesso che include un file audio.
TypeErrorquando fai cosa, esattamente? Questo di solito è un segno di avere il numero errato di argomenti durante l'istanza di un'istanza di classe. Se questo non fa parte del flusso di lavoro della domanda precedente, potresti pubblicarlo come un'altra domanda, inviarmelo tramite e-mail o aggiungerlo come problema sulla dillpagina di github?
dillproblema.
dilMi dà MemoryErrorperò! così fa cPickle, picklee hickle.
Puoi usare anycache per fare il lavoro per te. Considera tutti i dettagli:
picklemodulo Python per gestire lambdae tutte le belle funzionalità di Python.Supponendo di avere una funzione myfuncche crea l'istanza:
from anycache import anycache
class Company(object):
def __init__(self, name, value):
self.name = name
self.value = value
@anycache(cachedir='/path/to/your/cache')
def myfunc(name, value)
return Company(name, value)
Anycache chiama myfuncper la prima volta e sottrae il risultato a un file cachedirusando un identificatore univoco (a seconda del nome della funzione e dei suoi argomenti) come nome file. Ad ogni corsa consecutiva, l'oggetto in salamoia viene caricato. Se cachedirviene conservato tra le esecuzioni di Python, l'oggetto decapato viene prelevato dalla precedente esecuzione di Python.
Per ulteriori dettagli consultare la documentazione
anycacheper salvare più di un'istanza, per esempio, di un classcontenitore come list(non era il risultato della chiamata di una funzione)?
Esempio rapido usando company1dalla tua domanda, con 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"))
Tuttavia, come notato questa risposta , spesso il sottaceto fallisce. Quindi dovresti davvero usare 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"))