[Zope] Zope (X)3 FAQ

Dylan Reinhardt zope@dylanreinhardt.com
05 Apr 2003 11:32:08 -0800


On Sat, 2003-04-05 at 08:23, Thomas Guettler wrote:
> Example: You created instances of you class Foo. You have about 1000
> instances of this in the ZODB. Now you change the source of your
> python code, that all *new* objects get a birthday:
> 
> new code:
> 
> class Foo:
>     def __init__(self):
>         self.birthday=time.time()

Right... all *new* objects get a birthday.  

Since that's how you've described (and coded) the change, existing
objects won't have a birthday attribute until you give them one.  

If that's not what you want, then don't do it that way.


> If your application is already used by some people, you can't delete
> the 1000 existing objects which don't have a birthday. You need a way
> to update them. In this example you need to set the birthday for the
> old objects.

If you want existing objects to have immediate use of new attributes,
you need only code it that way.  There is no need to devise a workaround
for having mis-defined the requirement.

-----

class Foo(base_classes):
    def __init__(self):
        # avoid doing stuff here
        pass

    # add the following to a class with existing instances
    birthday = 0

    def set_birthday(self):
        self.birthday = time.time()

    def show_birthday(self):
        return self.birthday

-----

Now all existing instances will *immediately* have access to a birthday
attribute, since it is a class variable.  The moment you assign to
self.birthday, a new variable is created that is local to that
instance.  

Note, in particular, that it doesn't matter whether set_birthday() is
called before show_birthday().  The fact that there is a class variable
called birthday is sufficient to resolve the name.  You can think of the
class variable as a default or fall-through value.

If that default is changed, the changes will be immediately reflected in
all instances that *haven't* assigned a specific, overriding value.

Taking this a step further, it's probably a better idea to use class
variables to initialize attributes rather that putting them in
__init__() unless your *explicit intent* is to have different instances
preserving the assumptions they were created with.  Coding this way also
makes the current state of your objects more obvious from the code and
makes subclassing more transparent.

Class variables are particularly well-used when your instances are
storing some bit of information that's the same value among all (or
most) instances.  Note, for example, that this is how common attributes
such as meta_type and interfaces are implemented.  You *could* have
different instances determine (and remember) their own meta_type or
unique interface when they are initialized, but for the most part,
that's not what you want.  

> The solution is quite easy: All objects have a refreshAllObjects()
> method, which gets called from me if you do relevant changes. OK, this
> does not scale since all objects are touched, but it works for my
> use-case.

You can do this (and I have).  But it seems far easier to implement the
behavior you want than to create a kludge layer.

Dylan