On Thu, 22 May 2003 13:50:22 -0500
Luke Opperman <lu...@me...> wrote:
> 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.
This is when you call the class as a constructor. Just calling
__new__ gets all the lower level allocation in order and __init__
usually assigns values to __dict__. So since these values were
already assigned and we made them persistant in some way, they don't
have to be reassigned... Also consistency of the values was checked
during initial assignment so we can assume that the values we have are
consistent...
I'm wondering what pickle does--it's kind of the same problem. Does
it call __init__ during unpickling or just __new__??? While I haven't
looked into the details, I'm quite positive the latter holds..
> 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).
For what it's worth, some free flowing thoughts on the issue of
Person(12). It seems that our discussion so far has furthered each
others understanding (open source at work), so here some more
provocative thoughts:
A python class has only a single "constructor", ie. a combination of
__new__ and __init__. If you want multiple constructors, you have to
subclass. I do this regularly to provide different __init__ with a
signature specialized for different purposes. (And the rest of the
subclass is unchanged).
Applying this thought to Person(12), you really need an __init__ with
a different signature (12, instead of name=..., age=...), so a
subclass may be one solution. Is there a good naming convention for
this? Maybe GetPerson(12) where GetPerson is a subclass of Person?
But then, why does the act of retrieving an existing person from some
storage (or namespace, to think more generally) need to be a class
constructor? Why not Person.retrieve(12) or SQLObject.person(12) (both
class methods)? Or actually Persons.get(12) may be a good way of
putting it. (At least if the natural language of programming in
English and application programmers don't chose to end their class
names with and 's').
If you went that latter way, you could have Person('Ian', 'Bicking',
'autor of SQLObject') as a constructor instead of a classmethod
Person.new('Ian', 'Bicking', '...'). The former way seems to be what
I expect from plain Python. Is there any specific rational why you
reversed this?
> 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.
Not sure whether I misunderstand, so to find out here is how I think
about the issue. Every column corrsponds to a property whose setter
method is overloaded to store the object in the dbms. If application
programmers have a reason to (independently of SQLObject) make the
same attribute into a property, they have to possibly call SQLObject's
setter method from their setter method (in the same way as the
__init__ of a subclass usually calls the __init__ of the superclass).
One possible example of such as thing would be to log all state
changes to a file.
So if this understanding of what is happening is accurate, application
programmer need to take special steps when defining properties related
to columns. Or to avoid that, use the non-standard-python shortcut
method to define properties. So in any case, the way to define
properties (related to columns) is different from that of plain pyton.
In contrast, if column values are simply represented in the __dict__
of the instance, everything is as in plain python.
> 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.
Yes, you're right with the constraints--haven't thought of these
before. Moving from one consistent state of an object to another will
often require the change of more than one attribute. Same idea as
transactions...
The other reason why I feel unconfortable about updating on every
single attribute change is performance. Single attribute getter and
setter methods are an antipattern of distributed computing...
While SQLObject gives the possiblity to change several attributes at
once (with the set method), in my view this is quite awkward: it kind
of requires you to shadow the object with an object or an equivalent
unstructured collection of local variables to prepare the new state.
Usually, you would want to call several methods on the object in order
to prepare a new consistent state. If you allow attribute assignments
without committing, you can do that. The set method condemns you to
do the same without using any class methods and thus gets in the way..
Enough for today...
cheers
--bud
|