Serializzazione di oggetti

A volte abbiamo bisogno di salvare un oggetto sul disco per recuperarlo in un secondo momento, oppure può essere necessario inviare un oggetto attraverso la rete, a un altro programma Python in esecuzione su un’altra macchina.
Il processo di trasformare lo stato di un oggetto in un formato in grado che si possa memorizzare, recuperare e trasportare è conosciuto come serializzazione o marshalling.
In Python abbiamo diversi moduli che facilitano questo compito, come marshal, pickle, cPickle e shelve.
Moduli
Il modulo marshal è il più semplice e il più primitivo dei tre, e il suo scopo primario e la sua ragione di essere non è quella della serializzare degli oggetti, ma di lavorare con il bytecode di Python (file con estensione .pyc).
marshal permette serializzare solo oggetti semplici (la maggior parte dei tipi inclusi di default in Python), e non fornisce alcun meccanismo di sicurezza o di controlli a fronte di dati corrotti o non correttamente formattato. Inoltre, il formato usato per salvare il bytecode (e quindi il formato usato per memorizzare gli oggetti con marshal) può cambiare tra versioni, quindi non è adatto per la memorizzazione dati a lungo termine.
pickle, per parte sua, è in grado di serializzare quasi tutti gli oggetti (oggetti di tipi definiti dall’utente, collezioni contenenti collezioni, ecc) e ha alcuni meccanismi di sicurezza di base. Tuttavia, per essere più complesso di marshal, e, soprattutto, essendo scritto in Python al posto di C, come marshal, è anche molto lento.
La soluzione, se la velocità di serializzazione è importante per la nostra applicazione, è di utilizzare cPickle, ch’è un’implementazione in C di pickle. cPickle è fino a 1000 volte più veloce di pickle, e quasi veloce come marshal.
Se si tenta di importare cPickle e si produce un errore per qualche motivo, viene generata un’eccezione di tipo ImportError. Per utilizzare cPickle s’è disponibile e pickle altrimenti potremmo usare un codice simile al seguente:
         		try:
         		    import cPickle as pickle
         		except ImportError:
         		    import pickle
as in un import serve per importare l’elemento selezionato utilizzando un nome diverso, invece del suo nome.
Il modo più semplice per serializzare un oggetto utilizzando pickle è attraverso una chiamata a la funzione dump passando come argomento l’oggetto da serializzare e un oggetto file dove lo si salva (o qualsiasi altro oggetto simile a un file sempre che offra dei metodi di read, realine e write).
         		try:
         		    import cPickle as pickle
         		except ImportError:
         		    import pickle
         		
         		mio_file = file("dati.dat", "w")
         		animali = ["pitone", "mono", "camello"]
         		
         		pickle.dump(animali, mio_file)
         		
         		mio_file.close()
La funzione dump ha anche un parametro opzionale protocol che indica il protocollo da utilizzare durante il salvataggio. Il valore di default è 0, che utilizza il formato di testo ed è il meno efficiente. Il protocollo 1 è più efficiente di 0 ma inferiore a 2. Il protocollo 1 e 2 utilizzano un formato binario per memorizzare i dati.
         		try:
         		    import cPickle as pickle
         		except ImportError:
         		    import pickle
         		
         		mio_file = file("dati.dat", "w")
         		animali = ["pitone", "mono", "camello"]
         		
         		pickle.dump(animali, mio_file, 2)
         		
         		mio_file()
Per ricaricare un oggetto serializzato si utilizza la funzione load, che viene passato il file che si è salvato.
         		try:
         		    import cPickle as pickle
         		except ImportError:
         		    import pickle
         		
         		mio_file = file("dati.dat", "w")
         		animali = ["pitone", "mono", "camello"]
         		
         		pickle.dump(animali, mio_file)
         		
         		mio_file.close()
         		
         		mio_file = file("dati.dat")
         		
         		animali2 = pickle.load(mio_file)
         		print animali2
Ora supponiamo di voler archiviare un paio di liste in un file. Questo sarebbe così semplice come chiamare una volta a dump, per ogni lista, e quindi chiamare una volta load per ogni lista.
         		mio_file = file("dati.dat", "w")
         		animali = ["pitone", "mono", "camello"]
         		linguaggi = ["python", "mono", "perl"]
         		
         		pickle.dump(animali, mio_file)
         		pickle.dump(linguaggi, mio_file)
         		
         		mio_file = file("dati.dat")
         		
         		animali2 = pickle.load(mio_file)
         		linguaggi2 = pickle.load(mio_file)
         		print animali2
         		print linguaggi2
Ma cosa succederebbe se avessimo salvato 30 oggetti e volessimo accedere all’ultimo? Oppure, se ci ricordiamo in quale posizione l’ avevamo salvato? Il modulo shelve estende pickle/cPickle per fornire un modo per eseguire la serializzazione in modo più chiaro e semplice, in cui saremo in grado di accedere alla versione serializzata di un oggetto attraverso una stringa associata, simile ad una struttura come un dizionario.
L’unica funzione ch’è necessario conoscere dal modulo shelve è open, che conta con un parametro filename per indicare il percorso di un file in cui memorizzare gli oggetti (si può effettivamente creare più di un file, con nomi basati su filename, ma questo è trasparente per l’utente).
La funzione open ha anche un parametro opzionale protocol, con la quale specificare il protocollo che si desidera utilizzare al di sotto con pickle.
Come risultato della chiamata a open si ottiene un oggetto Shelf, con il quale possiamo lavorare come se si trattasse di un normale dizionario (a eccezione che le chiavi possono essere solo stringhe) per memorizzare e recuperare i nostri oggetti.
Come un dizionario qualsiasi la classe Shelf ha dei metodi come get, has_key, items, keys, values, …
Una volta che abbiamo terminato di lavorare con l’oggetto Shelf, lo chiudiamo con il metodo close.
         		import shelve
         
         		animali = ["pitone", "mono", "camello"]
         		linguaggi = ["python", "mono", "perl"]
         		
         		shelf = shelve.open("dati.dat")
         		shelf["prima"] = animali
         		shelf["seconda"] = linguaggi
         		
         		print shelf["seconda"]
         		
         		shelf.close()


Similari
Overloading di metodi in Java
12% Java
Un metodo overload viene utilizzato per riutilizzare il nome di un metodo ma con argomenti diversi, opzionalmente con un differente tipo di ritorno. [expand title=”Regole per overload” startwrap=”” endwrap=”” excerpt=”⤽” s…
Modi di fare e di non fare in Python
11% Python
Questo documento può essere considerato un compagno del tutorial di Python. Viene illustrato come utilizzare Python, e quasi ancora più importante, come non usare Python. [expand title=”Costrutti del linguaggio che non dov…
redirect 301 usando mod_alias
9% Server
mod_alias è fondamentalmente la versione più semplice di mod_rewrite. Non può fare le cose che fa mod_rewrite, ad esempio modificare la stringa di query. Per eseguire reindirizzamenti nel server web Apache è possibile di u…
Installare Python e Django su Windows
8% Django
Quando ci riferiamo allo sviluppo web con Python, la prima cosa che viene in mente è usare un qualche framework. Il più famoso e utilizzato da tutti è il Django, ma non è l’unico. Ci sono Pylons, Grok, TurboGears e Zope: t…
Metodi magici e costanti predefinite in PHP
8% Php
PHP fornisce un insieme di costanti predefinite e metodi magici per i nostri programmi. A differenza delle normali costanti i quali si impostano con define(), il valore delle costanti predefinite o speciali dipendono da do…