constructin trees in python

Aaron Sterling aaronasterling at gmail.com
Mon Nov 22 00:04:55 CET 2010


> Thanks a lot peter, that worked as i needed. Where can i find some
> good documentation which explains such behavior.

The reason for this behavior is the way python stores attributes.

Both a class and an instance of a class have a __dict__ attribute
which is a dictionary which stores attributes in name value pairs.

Consider the following class.

class A(object):
    a = 1

    def __init__(self, b):
        self.b = b


Inspecting A.__dict__, one will see that it looks like {'a': 1} with
no reference to b.

Instantiating with a = A(2), one will see that a.__dict__ is {'b': 2}
with no reference to a.

If one accesses a.b, then Python will first look in a.__dict__ and
find 'b'. It will then return that value for a.b

If one instead accesses a.a then Python will first look in a.__dict__
and not find an entry for 'a'. It will then look in type(a).__dict__
== A.__dict__, find 'a' and return it for a.a

One can in fact use this behavior to shadow class attributes. If the
__init__ function is changed to

    def __init__(self, a, b):
        self.a = a
        self.b = b

then all instances of A will have their own instance attribute named a
with whatever value is passed to __init__. They will still have a
class level attribute named a with value 1 but Python will never see
it because it will find an entry for a in some_instance.__dict__. If
one executes

    del some_instance.a

Then on that one instance, visibility for the class level a will be
restored. In fact, one can always get the class level instance as
type(some_instance).__dict__['a'] but that's a little awkward.

The reason that this matters with mutable attributes and not with
(often) with immutable attributes is that a statement of the form

     some_instance.some_mutable_attribute.append(foo)

will reference the same class level attribute regardless of the
instance it's called with. There's no assignment going on here. An
existing binding is being looked up, and the resulting value (a list
in this case) is having an attribute called on it. No new bindings are
being created. A statement of the form

     some_instance.some_mutable_attribute = some_new_list

Will not affect the class level attribute at all but will simply
shadow it in the same manner as describe above. Once a name is bound
to an immutable value, the only way to change the value that it points
to is to rebind it. This means that any 'change' to a class level
immutable value (accessed through attribute lookup on an instance)
will simply shadow it on the instance upon which it is accessed.

HTH



More information about the Python-list mailing list