[Zope3-Users] What attributes are made persistent

Jeff Shell eucci.group at gmail.com
Wed Feb 15 01:07:58 EST 2006


On 2/14/06, Peter Bengtsson <mail at peterbe.com> wrote:
> D'oh! That's confusing. Isn't there a class that gathers all of these in one.
>
> It seems confusing, you derive from Persistent but only some are accepted.
> Does that mean that there's PersistentFloat and PersistentTuple too?
> If not, why *only* dicts?

As mentioned above, it applies to *mutable* objects.

"""
Objects whose value can change are said to be mutable; objects whose
value is unchangeable once they are created are called immutable. (The
value of an immutable container object that contains a reference to a
mutable object can change when the latter's value is changed; however
the container is still considered immutable, because the collection of
objects it contains cannot be changed. So, immutability is not
strictly the same as having an unchangeable value, it is more subtle.)
An object's mutability is determined by its type; for instance,
numbers, strings and tuples are immutable, while dictionaries and
lists are mutable.
"""
http://docs.python.org/ref/objects.html

Instances of Persistent based classes know when they change. Like if you do::

    clive.age = 28

Which is effectively ``setattr(clive, 'age', 28)``. As a persistent
object, clive notices that an attribute is being set (even if it's
replacing an existing value), and flags that 'clive' has changes that
need to be saved. So again - here, it's the 'clive' object that's
being updated in this case. The fact that the value is an integer
doesn't matter. It's not changing. 28 is 28. But 'clive' is changing
by having a new/updated 'age' attribute set.

On the other hand, if you do::

    clive.favoriteNumbers.append(13)

'clive' does not change. 'favoriteNumbers' changes. If favoriteNumbers
is a regular Python list, the persistence machinery has no idea that
it's changed. It's not being assigned to 'clive', it's already an
attribute there and is not being replaced. So if it's not a
PersistentList, it gets forgotten.

If favoriteNumbers was a tuple, you couldn't append to it. You could
do an addition, but in a form like this::

    clive.favoriteNumbers = clive.favoriteNumbers + (13,)
    # Alternately
    clive.favoriteNumbers += (13,)

This is doing assignment. 'clive' is getting a new attribute set, and
as a Persistent object 'clive' can be set as needing its changes
saved.

It's not only dicts, it's dicts and lists (PersistentDict and PersistentList).

I don't know if there's a PersistentSet. Python offers two sets since
2.3 - a mutable (list-like) one and an immutable (tuple-like) one. I
imagine that if you use the mutable set (``sets.Set`` in 2.3, ``set``
in 2.4), you'd run into the same problems. But if you used the
immutable set (``sets.ImmutableSet``, ``frozenset`` in 2.4) you
wouldn't.

Note that this issue affects not just ZODB persistence. If you used
even the simple 'shelve' module that's in Python, you have the same
issue unless you use a 'writeback' option:

"""
If the writeback parameter is True, the object will hold a cache of
all entries accessed and write them back to the dict at sync and close
times. This allows natural operations on mutable entries, but can
consume much more memory and make sync and close take a long time.
"""

So as a way of making working with default mutable objects feel
natural, this option makes shelve read and write its whole database,
which would obviously be very expensive for the ZODB.

So - just use PersistentList and PersistentDict (or look into BTrees
for better storage options).

For more details, visit the ZODB documentation on ZODB programming,
and visit the section on modifying mutable objects:

http://www.zope.org/Wikis/ZODB/FrontPage/guide/node3.html


More information about the Zope3-users mailing list