[Grok-dev] adding objects to context from __init__
Brandon Craig Rhodes
brandon at rhodesmill.org
Sat Oct 4 18:03:27 EDT 2008
John de la Garza <john at jjdev.com> writes:
> In the tutorial the first demo of persistent objects did this:
>
> class Sample(grok.Application, grok.Container):
> text = 'default text'
The difference you are seeing has do to with how Python works. Roughly
speaking, when you ask an object for its "foo" attribute with something
like "print mysample.foo", it looks:
- For a "foo" attribute on the "mysample" instance.
- For a "foo" attribute on the class "Sample".
- For a "foo" attribute on all the parent classes of "Sample".
- For a "foo" attribute on the metaclass.
And Python returns the first value discovered. So, when you say:
class Sample(grok.Application, grok.Container):
text = 'default text'
you are creating a "safety" or "fall-through" value that will be
returned if an object is asked for its attribute "text" but does not
actually have one. So:
>>> s = Sample()
>>> print s.text
'default text'
>>> s.text = 'not the default text'
>>> print s
'not the default text'
You see? Until the "s" instance is given its own value for "text", it
uses the default one stored up in the class.
> Then as the tutorial goes on they do this:
>
> class Sample(grok.Application, grok.Container):
> def __init__(self):
> super(Sample, self).__init__()
> self.list = []
>
> Why don't we have to add the string the same way as the list? I mean
> the variable text gets persisted between restarts of the server, but
> if we added a list by doing this:
>
> class Sample(grok.Application, grok.Container):
> list = []
I apologize if my using capital letters looks offensive, but I'm really
just trying to be very, very clear:
- The variable "text" on the CLASS does NOT get persisted or stored
ANYWHERE and is re-created each time you run your application. So:
class Sample(...):
text = 'default text'
does NOT store ANYTHING for "text" in the database no matter how many
Sample objects you make.
- The assignment to an object attribute DOES save a value to that
INSTANCE in the database, without changing the definition your CODE
gives of the class. So:
>>> s = Sample()
>>> s.text = 'something else'
DOES save the new value of "text" to the database when you finish the
current transaction (in Zope, usually by completing the current web
operation, but you can also: "import transaction; transaction.commit()").
- This means that if you start up your application with new code that
reads slightly differently:
class Sample(...):
text = 'different default text'
that EVERY instance that never got ITS OWN value for "text" assigned
will now start returning 'different default text' when you ask for
its ".text" because, since it doesn't have ITS OWN value around in
the database, it just shows its class's value instead. But the
instances that DO have their OWN value just keep returning it, and
are not affected (unless you do a "del thissample.text" on them,
which stops them from having their own ".text" any more and they WILL
begin showing the class's value again).
- To now answer your actual question: the reason that we CANNOT do the
same trick with a list:
class Sample(grok.Application, grok.Container):
list = [] # BAD
is that we do NOT alter lists by reassignment; that is, we do NOT say
something like:
>>> s = Sample()
>>> s.list = [ 3,4,5 ]
when we want to alter its list. If we did, then all the above rules
would work, and we would be fine. But what we tend to do INSTEAD is:
>>> s = Sample()
>>> s.list.append(3)
>>> s.list.append(4)
which would NOT give "s" its OWN value for ".list", DIFFERENT than
everyone else's value for it, but would make changes to the SHARED
value of ".list" that's kept up in the class.
Since the ".list" attribute will just keep being MODIFIED, but never
REASSIGNED, we need to create a SEPARATE copy of the value on EVERY
class member and CANNOT safely provide a single default kept up on
the class instead of in the database. That is why you are seeing:
class Sample(grok.Application, grok.Container):
def __init__(self):
super(Sample, self).__init__()
self.list = []
Again, sorry for all the caps; but an old German named Marshall Booth
used to use capital letters like this when explaining things to we young
people on the Mercedes mailing list, and it really helped. So I thought
I would see if they would help here, just this once. :-)
--
Brandon Craig Rhodes brandon at rhodesmill.org http://rhodesmill.org/brandon
More information about the Grok-dev
mailing list