Global variables within classes.

Marc 'BlackJack' Rintsch bj_666 at gmx.net
Sat Nov 10 18:39:04 CET 2007


On Sat, 10 Nov 2007 18:53:08 +0200, Donn Ingle wrote:

> Included again for clarity:
>>> class Test:
>>>     attribute = "original value"
>>>     
>>> class Bob:
>>>     def __init__(self):
>>>         self.ref = Test()
>>>         
>>> class Jim:
>>>     def __init__(self):
>>>         self.ref = Test()
>>>         
>>> b = Bob()
>>> j = Jim()
>>> 
>>> print b.ref.attribute #prints "original value"
>>> b.ref.attribute = "haschanged"
>>> ## Where is the value "haschanged" going here?
>> 
>> To *instance* of `Test` you created and bound to `b.ref`.
>> 
> I don't follow you here. I *think* you are saying I created a *new* (on the
> fly) ref within b that is also called 'attrib', so that it's kind of
> shadowing the original 'attribute' ref (the so-called class attribute.)
> ?

In the `__init__()` of `Bob` you created an instance of `Test`.  You can't
create a `ref`, that's just a name of an attribute on `Bob` instances. 
Then you bind the attribute `attribute` of that instance to the string
"haschanged".  This assignment creates the attribute because `Test`
*instances* don't have such an attribute.  And yes this `attribute`
shadows the class `attribute` as the lookup rules are instance -> class ->
base classes.

>>> print b.ref.attribute # print "haschanged"
>>> 
>>> print j.ref.attribute #prints "original value"
>>> ## If it changed and an attribute of the Class, then
>>> ## why is it back to "original value" ?
>> 
>> Because the *instance* of `Test` bound to `j.ref` does not have
>> `attribute` it is looked up in the *class* `Test`.
> Okay, I sort of see that. It's not a property of 'j' so it looks upwards
> into the class.

Its not an attribute of `j.ref`!

Here's a little ASCII art showing the situation after your code was
executed::

  Names  |    Objects
  -------+---------------------------------------------
         |    +----------+
  Test ------>|<class>   |          +----------------+
         |    |attribute----------->|<str>           |
         |    +----------+          |"original value"|
         |                          +----------------+
         |
         |    +------+
  j --------->|<Joe> |   +----------+
         |    |ref  ---->|<Test>    |
         |    +------+   +----------+
         |
         |
         |    +------+
  b --------->|<Bob> |   +----------+
         |    |ref  ---->|<Test>    |   +------------+
         |    +------+   |attribute---->|<str>       |
         |               +----------+   |"haschanged"|
         |                              +------------+

On the left are the names in the module's namespace and on the right are
the objects in memory.  From the `Test` objects there's also a reference
to the `class` that's bound to the name `Test` in the Module that is not
shown in the "drawing" but necessary to look up attributes in the class of
the instances.

> This is kind of weird. It's not clear like Python usually is. Is this
> something intentional or did it 'fall through the cracks'? I mean, can one
> rely on it or will it be 'fixed'?

Don't think so.  It's a surprise for many but then class attributes are
not that common in code or they even use this "gotcha" for
immutable default values.  As long a the value isn't changed the default
value is just referenced from the class then and not every instance.

Ciao,
	Marc 'BlackJack' Rintsch



More information about the Python-list mailing list