The differences and interactions between class variables and instance variables are well described in the Python 2.x documentation, but they can be slightly subtle in some cases and I recently spent quite some time troubleshooting an issue even though I should have known better.
To put it simply, class variables are defined outside of any method of the class, normally right below the doc string. Class variables can be referenced directly from the class, and this can be used as one way to make an enumerated constant, or they can be referenced from any instance in the class. Instance variables are defined inside a method, normally __new__ or __init__, and they are local to that instance.
For a simple, contrived example:
class TestClass(object): c = 299792458 #this is a class variable def __init__(self): self.e = 2.71 #instance variable def phiFunc(self): self.phi = 1.618 #will become an instance variable after phiFunc is called x=224 #this is a method variable and can't be accessed outside this method assert TestClass.c == 299792458 try: print TestClass.e #Not defined except AttributeError: pass testInst = TestClass() assert testInst.c == 299792458 #instance gets c, currently a ref to the class var assert testInst.e == 2.71 #got e because of __init__ try: print testInst.phi #error since not defined yet except AttributeError: pass testInst.phiFunc() assert testInst.phi == 1.618 #now its here try: testInst.x #still undefined except AttributeError: pass
Class variables can be useful for constants that will need to be used by all instances of the class, or that are meant to be accessed directly from the class. They can also be used to set defaults for instance variables. But there it is important to remember that if the value of a class variable is changed, then all instances that call to the class variable will reflect that change. So, to carry on with our contrived TestClass:
TestClass.c = 1 assert testInst.c == 1 #Referring back to the class, so it changed too.
But when an instance has an attribute of the same name as an instance that essentially hides the class attribute. And assigning a value to an attribute of an instance will assign it just to that instance attribute, even if it needs to create it to do it. So:
class testClass2 (object): sqrttwo = 1.41 sqrrtthree = 1.73 def __init__(self): self.sqrttwo = 1 assert testClass2.sqrttwo == 1.41 #access class variable testInst2 = testClass2() assert testInst2.sqrttwo == 1 #the instance variable hides the class variable testInst2.sqrrtthree = 2 #assigning creates an instance attribute assert testClass2.sqrrtthree == 1.73 #So the value in the class is unchanged
This can get complicated when the class variable is a mutable type, like a list. Python handles assignment by reference, rather than by making a copy. For instance:
class classWList(object): defaultList = [1,] def __init__(self): self.instList = self.defaultList instance = classWList() assert instance.instList == [1,] #same as defaultList instance.instList.append(2) assert classWList.defaultList == [1, 2] #the class variable also has 2 now. assert id(classWList.defaultList) == id(instance.instList) #they point to the same memory address
Of course, that could be handled by explicitly making a copy instead of a simple assignment.
In short, both class variables and instance variables are useful, but there can be some subtleties to the way they interact that need to be remembered when working with them.
I just found a closely related post on Python Conquers the Universe titled “Gotcha — Mutable default arguments” that is well worth reading.
Nice, clear explanation. I’ve been away from python for a bit and this was a very useful refresher. Examples are great. Thanks.
Pingback: Python:Python read-only property – IT Sprite
Pingback: Essential Reads for Any Python Programmer – Notes By A Nerd
Pingback: Python Class Attributes: An Overly Thorough Guide - Codango™
Pingback: Python Class Attributes | abgoswam's tech blog