[ZODB-Dev] Is any function called when an object is loaded from the database?

Claudiu Saftoiu csaftoiu at gmail.com
Tue Jun 19 17:54:21 UTC 2012


Hello all,

It is often the case that I have a Persistent object that evolves over
time. E.g., it might start off as this:

    class Foo(Persistent):
        def __init__(self, a):
            self.a = a
        def calc_it(self, b):
            return expensive_function(a, b)

I'll then have a few hundred Foos in my database. Then I'll want to modify
the object, for example to cache the previous calculation.
That is, I want this to be the case, now:

    class Foo(Persistent):
        def __init__(self, a):
            self.a = a
            self.b_cache = PersistentDict()
        def calc_it(self, b):
            if b in self.b_cache: return self.b_cache[b]
            res = expensive_function(a, b)
            self.b_cache[b] = res
            return res

However, this won't work with existing Foo objects, as they won't have the
`b_cache` attribute. Thus I have two options. One is
to make the modifications backwards-compatible, e.g.:

    class Foo(Persistent):
        def __init__(self, a):
            self.a = a
            self.b_cache = PersistentDict()
        def calc_it(self, b):
            if not hasattr(self, 'b_cache'): self.b_cache = PersistentDict()

            if b in self.b_cache: return self.b_cache[b]
            res = expensive_function(a, b)
            self.b_cache[b] = res
            return res

The other is to go through the database and add 'b_cache' to all the
existing objects. Neither of these is really appealing.
The former is OK, but if I have multiple functions that want to use the new
functionality I'll have to have the code all
over, and it won't be obviously separated. The latter is rather annoying as
I have to figure out wherever I have Foos and
write throwaway code to change them all.

Ideally I could do something like this:

    class Foo(Persistent):
        def __init__(self, a):
            self.a = a
            self.b_cache = PersistentDict()

        def __just_loaded__(self):
            if not hasattr(self, 'b_cache'): self.b_cache = PersistentDict()

        def calc_it(self, b):

            if b in self.b_cache: return self.b_cache[b]
            res = expensive_function(a, b)
            self.b_cache[b] = res
            return res

That is, a function called whenever the object is loaded, that does all the
necessary backwards-compatibility
work right there. It separates the backwards-compat code cleanly, and also
only updates the objects
as-needed... though still a minor performance hit as it does the check each
time the object is loaded.

Is there a way to do that last option? What's the best practice for this
sort of thing, in general?

Thanks,
- Claudiu
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.zope.org/pipermail/zodb-dev/attachments/20120619/2ccbbeb0/attachment.html>


More information about the ZODB-Dev mailing list