Null Disquisition

Lots of talk about nothing

« Back to blog

Python static class members and You

After getting yelled at for not grading my student's homework, I decided to ignore the threatening emails and continue doing what I feel like. Undergrads, know this: TAs don't really care about you - sorry. I was debugging some code built on top of my awesome HTMLParser, and kept having a really frustrating problem. Some of my class variables were not getting reset during the __init__ call. So I poke around and after a while discover (buried in my libraries)

class Foo:
    a = True
    b = []
    c = []
    def __init__(self):
                ""
It seems the class members a, b, and c are not getting reset when I instanciate becasue, quite simply, I am not resetting them in __init__. I originally put them there for prettiness (self.a, self.b, self.c is so cumbersome), and moving them back into __init__ fixed my problem. A little more digging reveals what is going on here. If you define a variable outside of a class method, the variable is implicitly made static.
class Foo:
    a = "Hello"
print Foo.a
>> Hello
These static members are accessed just like regular members, with the "self" object. For things like str, int, float, the value will seem to be reset when you create a new instance of the class. But what's really happening is when you alter the static variable, you are actually creating a new class variable (in memory) which overrides the static for the duration of that object. This is not true for lists and dicts. I assume this is because Python uses pointers for array-like structures and the static member is just a pointer here. So when you alter the static list (via __getitem__, append, remove, et al.) you are operating on the pointer, not a copy of the list.
class Foo:
    a = []
    def __init__(self):
        print self.a
        self.a.append(1)
f = Foo()
f = Foo()
f = Foo()
>> []
>> [1]
>> [1,1]
Depending on how you're structuring your code (or how good at Python you are) you might want this functionality. For me though, this was not the case, so I put everything back in __init__. Another good thing to point out is Python has a very convienent syntax for making a copy of an array.
a = [1,2,3,4]
        b = a
        c = a[:]
        b[0] = 5
        c[0] = 6
        print a
        print b
        print c
        >> [5,2,3,4]
        >> [5,2,3,4]
        >> [6,2,3,4]
Sometimes I miss pointers, but not really. -David