> While I'm surely not a Python wizzard, this kind of surprises me. So I
> ran a little test:
Indeed, my information was incomplete. Here's the real story:
class instantiation:
__init__ will be called if __new__ returns an instance of the same class.
2.2.1 has a bug that disobeys this, and will call __init__ regardless.
SQLObject always does full instantiation, not calling just __new__. I can't
find any direct documentation against just calling __new__, so I suppose
that's one way to avoid __init__. But it means you can't have something like
Person(12).
Other options are to return a different class (an SQLObjectCached?) in __new__,
as mentioned above, or to redefine __init__ to check for a cached version.
Thanks to exarkun on #python for the initial idea (some maybe-code here,
regarding cache syntax):
class Cacheable(type):
cached = Cache()
def __new__(klass, name, bases, attrs):
init = attrs.get('__init__', None)
def __init__(self, *args, **kw):
if init and not self.__class__.cached.get(id):
init(self, *args, **kw)
attrs['__init__'] = __init__
return type.__new__(klass, name, bases, attrs)
class C(object):
__metaclass__ = Cacheable
def __new__(cls, id=None):
inst = cls.cached.get(id,None):
if not inst:
inst = object.__new__(cls)
cls.cached.put(inst)
return inst
This is almost exactly what SQLObject does, except it doesn't override __init__
today. So it looks like it would be easy enough to make SQLObject behave
'more' appropriately...
Oh, and I'm not sure what we're talking about as far as properties go. When I
said 'manually defining properties will be ignored' i meant SQLObject doesn't
care about them, and they'll work fine.
Agree with your summary that some form of transaction handling is required, and
hence delayed updates, if you want to sanely handle attribute
constraints/collisions.
Enjoy,
- Luke
|