[Zope-CMF] Add attributes to class which already has instances in ZODB

Jeffrey P Shell jeffrey@cuemedia.com
Thu, 9 Jan 2003 11:49:13 -0700


If you're writing the class in Python, you can add a __setstate__ 
method to the class.  This is called when the ZODB loads an instance of 
your class into memory.  A ZopeLabs Cookbook recipe has some details 
and an example:

http://www.zopelabs.com/cookbook/1002251996

Some Python documentation can be found in the current Python docs:
http://www.python.org/doc/lib/pickle-inst.html

So if you have all of your instance attributes usually set up during 
__init__, and you add to that list later, you want to use __setstate__.

class Foo(Persistent):
	def __setstate__(self, v):
		Foo.inheritedAttribute('__setstate__')(self, v)
		if not hasattr(self, 'email'):
			self.email = ""    # or some default value

Another way is to put the attribute definitions inside the class block 
itself.  Due to Python's laws of mutability, you have to be careful 
what you put in here.  But putting an attribute in a class statement 
would cause all objects to pick up that attribute (they're really 
"Shared Instance" attributes).

class Foo(Persistent):
	email = ""
	
Of course, a better design would be to implement everything with 
getter/setter methods (or at least getters).  It makes changes to the 
class easier.

class Foo(Persistent):
	_email = ""

	def email(self):
		return self._email

	def set_email(self, email):
		self._email = email

This design pattern is best for Zope because you can keep the actual 
attribute hidden from Python Scripts, etc (they can't access names with 
underscores), and place different permissions on the 'email' and 
'set_email' methods.  You can also avoid acquisition surprises, since 
you can't acquire names beginning with an underscore.

Another way that 'def email' can be written in this situation is:

def email(self):
	if hasattr(self, '_email'):
		return self._email
	else:
		return ""

(or more succinctly):
def email(self):
	return getattr(self, '_email', "")

This is the easiest way to add new attribute-like values to objects, 
since the new methods will be usable by all existing instances, and you 
can add code into the methods themselves to deal with instances that 
don't have a certain attribute set.

--
Jeffrey P Shell


On Thursday, January 9, 2003, at 03:12  AM, Rainer Thaden wrote:

> Hi,
>
> let's say you've written a type-class for CMF with some attributes,
> but you are not sure, if there are attributes missing. When you notice
> that there are missing attributes it will be too late to change the
> class, because there are already some instances in the ZODB, which you
> can't assign the new attributes.
> What would you do to prevent this situation when developing the class?
> Is it possible to add some dummy attributes and assign them the
> appropriate name afterwards like
>
> Attribute list:
>   name=''  #'normal' attributes
>   birth=''
>   ext1=''  #dummy attributes
>   ext2=''
>
>   and then you notice that you need an attribute for an email and
>   write
>
>   email=ext1
>
>   inside the class.
>
> Will a call to email on the objects which are already in the ZODB
> resolve the right name?
>
> -- 
> Regards,
>  Rainer                          mailto:thadi@gmx.de
>
>
> _______________________________________________
> Zope-CMF maillist  -  Zope-CMF@zope.org
> http://lists.zope.org/mailman/listinfo/zope-cmf
>
> See http://collector.zope.org/CMF for bug reports and feature requests