[Zope] Re: [Zope-CMF] Persistent dictionaries

Tres Seaver tseaver@palladion.com
Fri, 24 Aug 2001 07:53:04 -0400


Thomas Olsen wrote:

> Hi
> 
> I'm working on a CMF Product which is based on PortalFolder and 
> PortalContent. This Folderish object contains some items which inherits from 
> OFS.SimpleItem.Item, Persistence.Persistent and Aquisition.Implicit.
> These items have (had) some properties which are speciel to their class. In 
> order to get around the problem with adding new attributes and having 
> instantiated objects which doesn't have the attributes I decided to keep the 
> attributes in a dictionary. So in my base class I did:
> 
> ---snip--------------------------------------------
> class AbstractElement(Persistent, Item, Implicit):
>     """ Abstract base class for Element objects. """
>     _attributes = PersistentMapping()
> 
>     def __getattr__(self, name):
>         if self._attributes.has_key(name):
>             return self._attributes[name]
>         else:
>             raise AttributeError, name
> ---snip--------------------------------------------


Note that this spelling make '_attributes' a "shared instance
attribute" (all instances of the class, or ony class derived
from it, will share the mapping.  Normally, I would expect to
see the '_attibutes' assigned either in the initializer::

       def __init__( self ):

           self._attributes = PersistentMapping()

or else "lazily"::

       _attributes = None;

       def __getattr__( self, name ):

           if self._attributes is None:
              self._attributes = PersistentMapping()

           if self._attributes.has_key( name ): #...

 
> and my derived classes look something like this:
> 
> ---snip--------------------------------------------
> class TextElement(AbstractElement):
>     """
>     text element.
>     """
>     meta_type = 'Text Element'
> 
>     def __init__(self, id):
>         self.id = id
>         self._attributes = {'value':'','html':'','alignment':''}
> 
>     def edit(self, value, html, alignment):
>         """ Update the properties """
>         self._attributes['alignment'] = str(alignment)
>         self._attributes['value'] = str(value)
>         self._attributes['html'] = utils._format_stx(self.value)
> ---snip--------------------------------------------
> 
> It works great - until the object gets unloaded from the memory :-(
> 
> What am I doing wrong?


Note as well that plaing with '__getattr__' in the presence of
the acquisition machinery could be classifieds as Deep Voodoo (tm);

The canonical solution to your problem is to set a "shared" value

for the new attribute on the class, with an appropriate default;

instances which don't have the attribute in their own '__dict__'

will find it in the class.  Where that solution is infeasible,
the pickling machinery offers the '__setstate__' hook, which is
called immediately on unpickling;  you would *really* prefer not
to use this hook, but it is available.


Tres.
-- 
===============================================================
Tres Seaver                                tseaver@zope.com
Zope Corporation      "Zope Dealers"       http://www.zope.com