# Pickling Persistent Objects

Persistent objects are designed to make the standard Python pickling machinery happy:

    >>> import pickle
    >>> from persistent.tests.cucumbers import Simple
    >>> from persistent.tests.cucumbers import print_dict

    >>> x = Simple('x', aaa=1, bbb='foo')

    >>> print_dict(x.__getstate__())
    {'__name__': 'x', 'aaa': 1, 'bbb': 'foo'}

    >>> f, (c,), state = x.__reduce__()
    >>> f.__name__
    '__newobj__'
    >>> f.__module__.replace('_', '') # Normalize Python2/3
    'copyreg'
    >>> c.__name__
    'Simple'

    >>> print_dict(state)
    {'__name__': 'x', 'aaa': 1, 'bbb': 'foo'}

    >>> import pickle
    >>> pickle.loads(pickle.dumps(x)) == x
    True
    >>> pickle.loads(pickle.dumps(x, 0)) == x
    True
    >>> pickle.loads(pickle.dumps(x, 1)) == x
    True

    >>> pickle.loads(pickle.dumps(x, 2)) == x
    True

    >>> x.__setstate__({'z': 1})
    >>> x.__dict__
    {'z': 1}

This support even works well for derived classes which customize pickling by overriding `__getnewargs__()`, `__getstate__()` and `__setstate__()`.

    >>> from persistent.tests.cucumbers import Custom

    >>> x = Custom('x', 'y')
    >>> x.__getnewargs__()
    ('x', 'y')
    >>> x.a = 99

    >>> (f, (c, ax, ay), a) = x.__reduce__()
    >>> f.__name__
    '__newobj__'
    >>> f.__module__.replace('_', '') # Normalize Python2/3
    'copyreg'
    >>> c.__name__
    'Custom'
    >>> ax, ay, a
    ('x', 'y', 99)

    >>> pickle.loads(pickle.dumps(x)) == x
    True
    >>> pickle.loads(pickle.dumps(x, 0)) == x
    True
    >>> pickle.loads(pickle.dumps(x, 1)) == x
    True
    >>> pickle.loads(pickle.dumps(x, 2)) == x
    True

The support works for derived classes which define `__slots__`. It ignores any slots which map onto the “persistent” namespace (prefixed with `_p_`) or the “volatile” namespace (prefixed with `_v_`):

    >>> from persistent.tests.cucumbers import SubSlotted
    >>> x = SubSlotted('x', 'y', 'z')

Note that we haven’t yet assiged a value to the `s4` attribute:

    >>> d, s = x.__getstate__()
    >>> d
    >>> print_dict(s)
    {'s1': 'x', 's2': 'y', 's3': 'z'}

    >>> import pickle
    >>> pickle.loads(pickle.dumps(x)) == x
    True
    >>> pickle.loads(pickle.dumps(x, 0)) == x
    True
    >>> pickle.loads(pickle.dumps(x, 1)) == x
    True
    >>> pickle.loads(pickle.dumps(x, 2)) == x
    True

After assigning it:

    >>> x.s4 = 'spam'

    >>> d, s = x.__getstate__()
    >>> d
    >>> print_dict(s)
    {'s1': 'x', 's2': 'y', 's3': 'z', 's4': 'spam'}

    >>> pickle.loads(pickle.dumps(x)) == x
    True
    >>> pickle.loads(pickle.dumps(x, 0)) == x
    True
    >>> pickle.loads(pickle.dumps(x, 1)) == x
    True
    >>> pickle.loads(pickle.dumps(x, 2)) == x
    True

`persistent.Persistent` supports derived classes which have base classes defining `__slots`, but which do not define attr:__slots__ themselves:

    >>> from persistent.tests.cucumbers import SubSubSlotted
    >>> x = SubSubSlotted('x', 'y', 'z')

    >>> d, s = x.__getstate__()
    >>> print_dict(d)
    {}
    >>> print_dict(s)
    {'s1': 'x', 's2': 'y', 's3': 'z'}

    >>> import pickle
    >>> pickle.loads(pickle.dumps(x)) == x
    True
    >>> pickle.loads(pickle.dumps(x, 0)) == x
    True
    >>> pickle.loads(pickle.dumps(x, 1)) == x
    True
    >>> pickle.loads(pickle.dumps(x, 2)) == x
    True

    >>> x.s4 = 'spam'
    >>> x.foo = 'bar'
    >>> x.baz = 'bam'

    >>> d, s = x.__getstate__()
    >>> print_dict(d)
    {'baz': 'bam', 'foo': 'bar'}
    >>> print_dict(s)
    {'s1': 'x', 's2': 'y', 's3': 'z', 's4': 'spam'}

    >>> pickle.loads(pickle.dumps(x)) == x
    True
    >>> pickle.loads(pickle.dumps(x, 0)) == x
    True
    >>> pickle.loads(pickle.dumps(x, 1)) == x
    True
    >>> pickle.loads(pickle.dumps(x, 2)) == x
    True