constructor vs initializer assignments

Andy Bensky (ab@infoseek.com)
Mon, 7 Mar 1994 18:37:25 +0800

When a class has static attribute assignments outside of any method
definitions do the assignments get made before or after the __init__ method
is run when creating a new class instance?

In this example the value of the instance attribute, bar, of the class foo,
is assigned during the __init__ method to a value passed in to the initializer.
The value assigned in the initializer is retained by the instance attribute.

>>> class foo:
... bar = 10
... def __init__(self,val):
... self.bar = val
...
>>> foo.bar
10
>>> a=foo(12)
>>> a.bar
12

The value of the instance attribute is the value assigned in the class
initializer function, __init__, and overrides the value assigned in the
class definition.

In the next example the initializer first prints out the value of the
instance and then changes the default value for the class. Since it
already has had it's own copy of the instance attribute, bar, assigned
to the value in the class definition, I would expect it to only change the
class value which would be applied to the next instance that is created and
leave the one in the instance being initialized alone.

>>> class foo:
... bar = 10
... def __init__(self):
... print self.bar
... foo.bar = foo.bar + 1
...
>>> foo.bar
10
>>> a=foo()
10
>>> a.bar
11
>>> foo.bar
11

>From the last 2 commands it is shown that the value of the instance attribute
is assigned after the initializer is executed. This behavior is opposite
what we saw in the first example

The next example shows that the assignment of self.bar is actually made
both before and after the initializer, depending on what happens during the
initializer.

>>> class foo:
... bar = 10
... def __init__(self):
... print self.bar
... self.bar = foo.bar
... foo.bar = foo.bar + 1
...
>>> foo.bar
10
>>> a=foo()
10
>>> a.bar
10
>>> foo.bar
11

In this example the value of the instance attribute is available at the
beginning of the initializer and is the same as the class default value.
The class default value is changed during the initializer just as it was
in example 2, above. But in this case the instance attribute value does
not change as it did in that example! It behaves more like it did in
the first example.

It appears that whether or not the instance attributes are assigned the value
of the class attributes is dependent on if an assignment is done to the instance
attribute in the initializer. If there is an explicit assignment of the
instance attribute in the initializer then the class attribute is not assigned.
If there is no explicit assignment of the instance attribute then it takes on
the value of the class attribute.

My guess is that if there is an explicit assignment then a new entry is made in
the dictionary for the instance. If there is no assignment then the instance
attribute is scoped to the class attribute.

The really strange point is that in the case where we print self.bar just
before the assignment of self.bar in the initializer I would expect an
error since the interpreter should see that there is a local self.bar and
scope the print statement to the local copy as in the following example:

>>> a=100
>>> def func():
... print a
... a = 10
...
>>> func()
Traceback (innermost last):
File "<stdin>", line 1
File "<stdin>", line 2
NameError: undefined local variable

What exactly are the rules concerning scope of intance and class attributes?
They don't seem to follow the same rules as scope of other variables.

Andy Bensky
InfoSeek Corp.