3.14.5.3 Serializzare e deserializzare oggetti esterni

Per ottenere vantaggi dalla persistenza degli oggetti, il modulo pickle supporta la nozione relativa di un riferimento ad un oggetto esterno al flusso dei dati serializzati. Questi oggetti vengono riferiti tramite un ``id persistente'', che consiste in una stringa arbritraria di caratteri ASCII stampabili. La risoluzione di questi nomi non viene definita dal modulo pickle, ma viene delegata alle funzioni definite dall'utente su pickler ed unpickler.3.8

Per definire esternamente la risoluzione di un id persistente, si ha bisogno di impostare l'attributo persistent_id nell'oggetto serializzatore, e l'attributo persistent_load dell'oggetto deserializzatore.

Per serializzare oggetti che hanno un id persistente esterno, il pickler deve avere un metodo personalizzato persistent_id() che prenda un oggetto come un argomento e restituisca o None oppure l'id persistente per quell'oggetto. Quando viene restituito None, il pickler semplicemente serializza l'oggetto come normale. Quando viene restituita una stringa di id persistente, il pickler serializzerà quella stringa attraverso un marcatore, così che il deserializzatore riconosca la stringa come id persistente.

Per deserializzare oggetti esterni, il deserializzatore deve avere una funzione personalizzata persistent_load(), che prenda una stringa id persistente e restituisca l'oggetto referenziato.

Ecco uno sciocco esempio che potrebbe fare un po' di luce:

import pickle
from cStringIO import StringIO

src = StringIO()
p = pickle.Pickler(src)

def persistent_id(obj):
    if hasattr(obj, 'x'):
        return 'il valore %d' % obj.x
    else:
        return None

p.persistent_id = persistent_id

class Integer:
    def __init__(self, x):
        self.x = x
    def __str__(self):
        return 'Il mio nome e` intero %d' % self.x

i = Integer(7)
print i
p.dump(i)

datastream = src.getvalue()
print repr(datastream)
dst = StringIO(datastream)

up = pickle.Unpickler(dst)

class FancyInteger(Integer):
    def __str__(self):
        return 'Io sono il numero %d' % self.x

def persistent_load(persid):
    if persid.startswith('the value '):
        value = int(persid.split()[2])
        return FancyInteger(value)
    else:
        raise pickle.UnpicklingError, 'ID persistente non valido'

up.persistent_load = persistent_load

j = up.load()
print j

Nel modulo cPickle, l'attributo persistent_load dell'unpickler può anche venire impostato su una lista Python, nel qual caso, quando l'unpickler incontra un id persistente, la sua stringa id viene semplicemente accodata a tale lista. Questa funzionalità esiste per far sì che un flusso di dati serializzati possa venire ``sniffato'' alla ricerca di riferimenti ad oggetti senza istanziare effettivamente tutti gli oggetti serializzati.3.9L'impostazione di persistent_load su una lista viene di solito usata congiuntamente a un metodo noload() nell'Unpickler.



Footnotes

... unpickler.3.8
Il meccanismo corrente per associare queste funzioni definite dall'utente è leggermente differente per pickle e cPickle. La descrizione qui fornita funziona allo stesso modo per entrambe le implementazioni. Gli utenti del modulo pickle potrebbero usare anche una sotto classe per ottenere gli stessi risultati, sovrascrivendo i metodi persistent_id() e persistent_load() nelle classi derivate.
... serializzati.3.9
Lascio a voi immaginare Guido e Jim seduti insieme a sniffare flussi serializzati nel loro soggiorno.
Vedete Circa questo documento... per informazioni su modifiche e suggerimenti.