3.14.5.3 Pickling and unpickling external objects
For the benefit of object persistence, the pickle module supports the notion of a reference to an object outside the pickled data stream. Such objects are referenced by a ``persistent id'', which is just an arbitrary string of printable ASCII characters. The resolution of such names is not defined by the pickle module; it will delegate this resolution to user defined functions on the pickler and unpickler.3.8
To define external persistent id resolution, you need to set the persistent_id attribute of the pickler object and the persistent_load attribute of the unpickler object.
To pickle objects that have an external persistent id, the pickler
must have a custom persistent_id() method that takes an
object as an argument and returns either None
or the persistent
id for that object. When None
is returned, the pickler simply
pickles the object as normal. When a persistent id string is
returned, the pickler will pickle that string, along with a marker
so that the unpickler will recognize the string as a persistent id.
To unpickle external objects, the unpickler must have a custom persistent_load() function that takes a persistent id string and returns the referenced object.
Here's a silly example that might shed more light:
import pickle from cStringIO import StringIO src = StringIO() p = pickle.Pickler(src) def persistent_id(obj): if hasattr(obj, 'x'): return 'the value %d' % obj.x else: return None p.persistent_id = persistent_id class Integer: def __init__(self, x): self.x = x def __str__(self): return 'My name is integer %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 'I am the integer %d' % self.x def persistent_load(persid): if persid.startswith('the value '): value = int(persid.split()[2]) return FancyInteger(value) else: raise pickle.UnpicklingError, 'Invalid persistent id' up.persistent_load = persistent_load j = up.load() print j
In the cPickle module, the unpickler's persistent_load attribute can also be set to a Python list, in which case, when the unpickler reaches a persistent id, the persistent id string will simply be appended to this list. This functionality exists so that a pickle data stream can be ``sniffed'' for object references without actually instantiating all the objects in a pickle.3.9 Setting persistent_load to a list is usually used in conjunction with the noload() method on the Unpickler.
Footnotes
- The actual mechanism for associating these user defined functions is slightly different for pickle and cPickle. The description given here works the same for both implementations. Users of the pickle module could also use subclassing to effect the same results, overriding the persistent_id() and persistent_load() methods in the derived classes.
- We'll leave you with the image of Guido and Jim sitting around sniffing pickles in their living rooms.