Python Class Members

One is a class attribute, while the other is an instance attribute. They are different, but they are closely related to one another in ways that make them look the same at times.

It has to do with the way python looks up attributes. There’s a hierarchy. In simple cases it might look like this:

instance -> Subclass -> Superclass -> object (built-in type)

When you look for an attribute on instance like this…

`instance.val`

…what actually happens is that first, Python looks for val in the instance itself. Then, if it doesn’t find val, it looks in its class, Subclass. Then, if it doesn’t find val there, it looks in the parent of Subclass, Superclass. This means that when you do this…

>>> class Foo():
    foovar = 10  
    def __init__(self, val):
        self.selfvar = val

…all instances of Foo share foovar, but have their own distinct selfvars. Here’s a simple, concrete example of how that works:

>>> f = Foo(5)
>>> f.foovar
10
>>> Foo.foovar
10

If we don’t touch foovar, it’s the same for both f and Foo. But if we change f.foovar

>>> f.foovar = 5
>>> f.foovar
5
>>> Foo.foovar
10

…we add an instance attribute that effectively masks the value of Foo.foovar. Now if we change Foo.foovar directly, it doesn’t affect our foo instance:

>>> Foo.foovar = 7
>>> f.foovar
5

But it does affect a new foo instance:

>>> Foo(5).foovar
7

Also keep in mind that mutable objects add another layer of indirection (as mgilson reminded me). Here, f.foovar refers to the same object as Foo.foovar, so when you alter the object, the changes are propagated up the hierarchy:

>>> Foo.foovar = [1]
>>> f = Foo(5)
>>> f.foovar[0] = 99
>>> Foo.foovar
[99]

Leave a Comment