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-------------------------------------------- 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? -- Regards, Thomas Olsen http://www.tanghus.dk
On Thu, 2001-08-23 at 17:54, Thomas Olsen wrote:
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?
Unless I miss my guess, this is because Zope doesn't persist changes to mutable subobjects automatically. Dictionaries (like lists) are mutable types, so you need to inform the persistence machinery that something has changed: self.__changed__(1) Immutable properties, such as strings or tuples, don't have this requirement. HTH, Michael Bernstein.
Yihaw - it seems to work between restarts. Actually I had read about it; I just assumed that PersistenMapping did this for me. Should have read the source more closely. Thanks! On Friday 24 August 2001 07:08, Michael R. Bernstein wrote:
It works great - until the object gets unloaded from the memory :-(
What am I doing wrong?
Unless I miss my guess, this is because Zope doesn't persist changes to mutable subobjects automatically. Dictionaries (like lists) are mutable types, so you need to inform the persistence machinery that something has changed:
self.__changed__(1)
Immutable properties, such as strings or tuples, don't have this requirement.
-- Regards, Thomas Olsen http://www.tanghus.dk
I think you mean: self._p_changed = 1 Andreas ----- Original Message ----- From: "Michael R. Bernstein" <webmaven@lvcm.com> To: "Thomas Olsen" <tol@tanghus.dk> Cc: <zope-cmf@zope.org>; <zope@zope.org> Sent: Freitag, 24. August 2001 01:08 Subject: Re: [Zope] Persistent dictionaries
Unless I miss my guess, this is because Zope doesn't persist changes to mutable subobjects automatically. Dictionaries (like lists) are mutable types, so you need to inform the persistence machinery that something has changed:
self.__changed__(1)
Immutable properties, such as strings or tuples, don't have this requirement.
Isn't that basically the same? On Friday 24 August 2001 12:15, Andreas Jung wrote:
I think you mean:
self._p_changed = 1
self.__changed__(1)
-- Regards, Thomas Olsen http://www.tanghus.dk
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
On Friday 24 August 2001 13:53, Tres Seaver wrote:
_attributes = PersistentMapping()
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.
Oops - that certainly wasn't intentionally... I'm still very much of a Python newbie. Must have mixed it up with something else. I thought it was the notation for a pseudo private attribute. Need to pickup "Programming Python" a bit more often :-)
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 ): #...
The lazy approach looks very sensible.
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);
:-) Are there any serious pitfalls I ought to know about?
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.
Been there - done that ;-) But not really successfully.
Tres.
-- Regards, Thomas Olsen http://www.tanghus.dk
On Fri, 24 Aug 2001, Thomas Olsen wrote:
On Friday 24 August 2001 13:53, Tres Seaver wrote:
_attributes = PersistentMapping()
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.
Oops - that certainly wasn't intentionally... I'm still very much of a Python newbie. Must have mixed it up with something else. I thought it was the notation for a pseudo private attribute. Need to pickup "Programming Python" a bit more often :-)
My mistake: I said "spelling" when I meant to say "location of the attribute assignment" (i.e., at class scope, rather than bound to 'self'); the leading underscore *does* signal (by convention in Python, and by check in Zope) "privateness" of the attribute.
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 ): #...
The lazy approach looks very sensible.
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);
:-) Are there any serious pitfalls I ought to know about?
I could tell you, but then you'd have to scrape your brains off of the ceiling. :) Seriously, acquisition itself relies on hooking '__getattr__' in fairly fiendish ways; I am reluctant to try any technique which might fight with it. Tres. -- =============================================================== Tres Seaver tseaver@zope.com Zope Corporation "Zope Dealers" http://www.zope.com
Thomas Olsen writes:
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--------------------------------------------
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':''} From here on "self._attributes" is no longer a PersistentMapping but a normal Python dictionary. Internal modifications do not trigger the persistence machinery. They would, if "_attributes" were still a PersistentMapping....
Dieter
On Friday 24 August 2001 23:46, Dieter Maurer wrote:
self._attributes = {'value':'','html':'','alignment':''}
From here on "self._attributes" is no longer a PersistentMapping but a normal Python dictionary. Internal modifications do not trigger the persistence machinery. They would, if "_attributes" were still a PersistentMapping....
Doh - didn't think of that... Anyway - I'm lying on the coach with the flu right now so my brain is even duller than usual :-) Something I don't quite understand about the python classes: Say you have an instance of a class MyClass with attributes myattr1 and myattr2; then you change the class definition for MyClass adding myattr3. If attributes are stored in dictionary __dict__ isn't it possible simply to do: def __getattr__(self, name): # or maybe __setstate__(self): if not self.hasattr(name): # add attribute name self.__dict__[name] = "" Shouldn't this add the attribute to the class instance? -- Regards, Thomas Olsen http://www.tanghus.dk
Thomas Olsen writes:
.... Say you have an instance of a class MyClass with attributes myattr1 and myattr2; then you change the class definition for MyClass adding myattr3. If attributes are stored in dictionary __dict__ isn't it possible simply to do:
def __getattr__(self, name): # or maybe __setstate__(self): if not self.hasattr(name): # add attribute name self.__dict__[name] = ""
Shouldn't this add the attribute to the class instance? Usually, it would not work.... Several reasons:
1. Your "__getattr__" would define any attribute that is not already there. I doubt this is useful... 2. Python calls "__getattr__" only the normal lookup was not successful. The normal lookup will find the class attribute "myattr3", "__getattr__" would not be called. Dieter
On Sunday 26 August 2001 00:09, Dieter Maurer wrote:
Say you have an instance of a class MyClass with attributes myattr1 and myattr2; then you change the class definition for MyClass adding myattr3.
Thomas Olsen writes: 2. Python calls "__getattr__" only the normal lookup was not successful. The normal lookup will find the class attribute "myattr3", "__getattr__" would not be called.
But if the object was instantiated before adding myattr3 to the class definition the objects __dict__ wouldn't contain it and you would get an AttributeError when trying to access it if you didn't implement __getattr__? -- Regards, Thomas Olsen http://www.tanghus.dk
(Sorry for this maybe irrelevant to you, my dear zope companion) Hi, Is there any python programer in Taiwan interested of finding a job in a company which fully adopt zope/python to service its clients. We can communicate in English. If you are not a taiwanese, it's fine. I promise not to ask you to write ASP (M$/IIS). But with a little knowledge about Macromedia Flash and *nix required. Please reply to iap@y2fun.com Thanks. Iap, Singuan Taipei, Taiwan
Thomas Olsen writes:
On Sunday 26 August 2001 00:09, Dieter Maurer wrote:
Say you have an instance of a class MyClass with attributes myattr1 and myattr2; then you change the class definition for MyClass adding myattr3.
Thomas Olsen writes: 2. Python calls "__getattr__" only the normal lookup was not successful. The normal lookup will find the class attribute "myattr3", "__getattr__" would not be called.
But if the object was instantiated before adding myattr3 to the class definition the objects __dict__ wouldn't contain it and you would get an AttributeError when trying to access it if you didn't implement __getattr__? The class dict is searched dynamically. Attributes are not copied at instance creation time. It is not necessary to implement "__getattr__" for this.
Dieter
participants (6)
-
Andreas Jung -
Dieter Maurer -
iap@y2fun.com -
Michael R. Bernstein -
Thomas Olsen -
Tres Seaver