Python class variables are variables declared inside a class but outside any instance method or __init__() method. They are shared among all instances of the class, meaning a single copy exists and is accessible via the class name or any instance.
Declaration: Defined at the class level, typically placed just below the class header.
Access: Can be accessed using
ClassName.variable_nameorinstance.variable_name.Shared State: Changes to a class variable via the class name affect all instances.
Use Cases: Ideal for constants, counters (e.g., tracking total instances), default configurations, or shared data (e.g., school name in a
Studentclass).
Example:
class Student:
school_name = "ABC School" # Class variable
def __init__(self, name):
self.name = name # Instance variable
s1 = Student("Emma")
s2 = Student("Jessa")
print(s1.school_name) # Output: ABC School
print(s2.school_name) # Output: ABC School
Student.school_name = "XYZ School"
print(s1.school_name) # Output: XYZ School (updated for all instances)Important: Modifying a class variable through an instance creates an instance variable with the same name, hiding the class variable for that instance. Always use the class name to modify class variables.
Inheritance: Derived classes inherit class variables from their base class and can access or override them.
This is because of the way Python resolves names with the .. When you write self.list the Python runtime tries to resolve the list name first by looking for it in the instance object, and if it is not found there, then in the class instance.
Let's look into it step by step
self.list.append(1)
- Is there a
listname into the objectself?- Yes: Use it! Finish.
- No: Go to 2.
- Is there a
listname into the class instance of objectself?- Yes: Use it! Finish
- No: Error!
But when you bind a name things are different:
self.list = []
- Is there a
listname into the objectself?- Yes: Overwrite it!
- No: Bind it!
So, that is always an instance variable.
Your first example creates a list into the class instance, as this is the active scope at the time (no self anywhere). But your second example creates a list explicitly in the scope of self.
More interesting would be the example:
class testClass():
list = ['foo']
def __init__(self):
self.list = []
self.list.append('thing')
x = testClass()
print x.list
print testClass.list
del x.list
print x.list
That will print:
['thing']
['foo']
['foo']
The moment you delete the instance name the class name is visible through the self reference.
Videos
What is a class variable in Python?
How do you define a class variable in Python?
What is a Python namespace?
A Python namespace is a mapping from names to objects, with the property that there is zero relation between names in different namespaces. Namespaces are usually implemented as Python dictionaries, although this is abstracted away.
This is because of the way Python resolves names with the .. When you write self.list the Python runtime tries to resolve the list name first by looking for it in the instance object, and if it is not found there, then in the class instance.
Let's look into it step by step
self.list.append(1)
- Is there a
listname into the objectself?- Yes: Use it! Finish.
- No: Go to 2.
- Is there a
listname into the class instance of objectself?- Yes: Use it! Finish
- No: Error!
But when you bind a name things are different:
self.list = []
- Is there a
listname into the objectself?- Yes: Overwrite it!
- No: Bind it!
So, that is always an instance variable.
Your first example creates a list into the class instance, as this is the active scope at the time (no self anywhere). But your second example creates a list explicitly in the scope of self.
More interesting would be the example:
class testClass():
list = ['foo']
def __init__(self):
self.list = []
self.list.append('thing')
x = testClass()
print x.list
print testClass.list
del x.list
print x.list
That will print:
['thing']
['foo']
['foo']
The moment you delete the instance name the class name is visible through the self reference.
Python has interesting rules about looking up names. If you really want to bend your mind, try this code:
class testClass():
l = []
def __init__(self):
self.l = ['fred']
This will give each instance a variable called l that masks the class variable l. You will still be able to get at the class variable if you do self.__class__.l.
The way I think of it is this... Whenever you do instance.variable (even for method names, they're just variables who's values happen to be functions) it looks it up in the instance's dictionary. And if it can't find it there, it tries to look it up in the instance's class' dictionary. This is only if the variable is being 'read'. If it's being assigned to, it always creates a new entry in the instance dictionary.
Neither way is necessarily correct or incorrect, they are just two different kinds of class elements:
- Elements outside the
__init__method are static elements; they belong to the class. - Elements inside the
__init__method are elements of the object (self); they don't belong to the class.
You'll see it more clearly with some code:
class MyClass:
static_elem = 123
def __init__(self):
self.object_elem = 456
c1 = MyClass()
c2 = MyClass()
# Initial values of both elements
>>> print c1.static_elem, c1.object_elem
123 456
>>> print c2.static_elem, c2.object_elem
123 456
# Nothing new so far ...
# Let's try changing the static element
MyClass.static_elem = 999
>>> print c1.static_elem, c1.object_elem
999 456
>>> print c2.static_elem, c2.object_elem
999 456
# Now, let's try changing the object element
c1.object_elem = 888
>>> print c1.static_elem, c1.object_elem
999 888
>>> print c2.static_elem, c2.object_elem
999 456
As you can see, when we changed the class element, it changed for both objects. But, when we changed the object element, the other object remained unchanged.
I think this sample explains the difference between the styles:
james@bodacious-wired:~$cat test.py
#!/usr/bin/env python
class MyClass:
element1 = "Hello"
def __init__(self):
self.element2 = "World"
obj = MyClass()
print dir(MyClass)
print "--"
print dir(obj)
print "--"
print obj.element1
print obj.element2
print MyClass.element1 + " " + MyClass.element2
james@bodacious-wired:~$./test.py
['__doc__', '__init__', '__module__', 'element1']
--
['__doc__', '__init__', '__module__', 'element1', 'element2']
--
Hello
World
Traceback (most recent call last):
File "./test.py", line 17, in <module>
print MyClass.element2
AttributeError: class MyClass has no attribute 'element2'
element1 is bound to the class, element2 is bound to an instance of the class.