Python class variables and instance variables are the two fundamentally different ways that data can be stored in an object-oriented program, and confusing them is one of the most common sources of bugs in Python classes. A class variable is defined directly in the class body, outside any method, and there is exactly one copy of it shared across every instance of that class. An instance variable is defined inside a method, typically the constructor, using dot notation on the object reference parameter, and every instance gets its own independent copy. The distinction matters because it determines whether changing a value on one object affects other objects, whether that value persists across the program's lifetime, and whether the attribute is accessible before any instances are created. The articles on Python class attributes and Python instance attributes covered each type in detail. This article compares them side by side, focusing on the design decisions that determine which type to use in different situations.
The decision between class and instance variables is not always obvious, and even experienced Python developers sometimes reach for the wrong one. The most reliable test is to ask whether the attribute should have the same value for every object of the class. A setting that configures how all objects of a class behave, like a database connection timeout or a default page size, should be a class variable. A piece of data that distinguishes one object from another, like a customer's name or an order's total, should be an instance variable. The test is simple, but the edge cases, particularly around mutable class variables and the shadowing behavior when assigning through an instance, require careful understanding.
The shadowing behavior is the single most important gotcha to internalize. Reading an attribute through an instance follows Python's lookup order: the instance is checked first, and if the attribute is not found there, the class is checked. This means reading a class variable through an instance works correctly and returns the shared value. But assigning to an attribute through an instance always creates or modifies an instance variable, never a class variable. If you intend to modify the shared class value but assign through an instance, you silently create an instance-specific override that shadows the class value for that one object while leaving the class value unchanged for every other object. This bug produces no error messages and no warnings; the data is simply wrong in a way that can be very hard to trace.
Side-by-side comparison with a practical example
A single class that uses both types of variables makes the distinction concrete. Consider a class that represents an employee in a company directory. Every employee has a name and an ID number, which vary from employee to employee and should be instance variables. The company has a standard work week in hours, which is the same for all employees and should be a class variable:
class Employee:
standard_hours = 40
total_employees = 0
def __init__(self, name, employee_id):
self.name = name
self.employee_id = employee_id
Employee.total_employees += 1The name and employee ID are instance variables set in the constructor and unique to each employee. The standard work week is a class variable that every employee shares; if the company changes its policy, updating Employee.standard_hours changes the value for all objects. The total employees counter is a class variable that tracks how many Employee instances have been created, incremented in the constructor each time a new employee is created.
Reading these attributes through an instance shows how Python's lookup order resolves them. Accessing an employee's name goes directly to the instance variable. Accessing standard_hours through an instance finds no instance variable with that name and falls back to the class variable. Accessing total_employees through the class name returns the shared counter. The lookup is invisible to the caller, which is convenient for reading but dangerous for writing, as the next section demonstrates.
The shadowing trap in detail
The most instructive example of the shadowing behavior is a class variable that holds a configuration value, where a developer intends to override it for a specific instance. The following code demonstrates both the correct way to read a class variable and the subtle mistake of assigning through an instance:
class Service:
timeout = 30
api = Service()
worker = Service()
print(api.timeout)Both instances print 30 because neither has its own timeout attribute, and both fall back to the class variable. Now suppose the developer wants to give the API service a longer timeout:
api.timeout = 60
print(api.timeout)
print(worker.timeout)
print(Service.timeout)The output is 60, 30, 30. The assignment api.timeout = 60 created a new instance variable on the api object that shadows the class variable. The worker object still sees the class value of 30 because it has no shadowing instance variable. The class itself still has 30 because the assignment through the instance did not modify the class variable. If the developer's intent was to change the timeout for all services, they should have written Service.timeout = 60. If the intent was to give just the API service a different timeout, the instance assignment is correct, but the developer should understand that they are creating an instance override, not modifying a shared value.
The same trap applies to mutable class variables. If a class has a list as a class variable and a method appends to that list through the instance, the append modifies the shared list correctly because the read of the attribute resolves to the class variable and the append method mutates the list in place. But if the method assigns a new list through the instance, that assignment creates a shadowing instance variable, breaking the sharing. The rule of thumb is to always access class variables through the class name when modifying them, using the instance access only for reading.
Choosing the right variable type
When the attribute's value should be the same for every instance, use a class variable. This includes configuration constants, default values that instances rarely override, counters and registries that span all instances, and any data that describes the class as a whole rather than individual objects. Class variables are also appropriate when you need to access the data before any instances exist, since class variables are available as soon as the class is defined.
When the attribute's value should vary from instance to instance, use an instance variable. This includes any data that identifies or describes a specific object, such as names, IDs, timestamps, measurements, and status flags. Instance variables are created in the constructor and are the default choice for any attribute that you expect to be different for each object.
The article on encapsulation in Python covers how to protect both class and instance variables from unintended external access using underscore conventions and properties. The protection mechanisms work the same way regardless of whether the underlying data is stored at the class level or the instance level.
Rune AI
Key Insights
- Class variables are defined in the class body and shared across all instances; instance variables are defined in methods and unique to each object.
- Use class variables for constants, defaults, and shared counters; use instance variables for per-object data.
- Assigning to a class variable through an instance creates a shadowing instance variable rather than modifying the class variable.
- Always access class variables through the class name when modifying them to avoid the shadowing trap.
- Mutable class variables like lists require extra care because all instances share the same mutable object.
Frequently Asked Questions
What is the difference between a class variable and an instance variable in Python?
What happens if I assign to a class variable through an instance?
How do I decide whether an attribute should be a class variable or an instance variable?
Conclusion
Class variables and instance variables serve different purposes in Python's object model, and understanding the distinction is essential for designing classes that behave predictably. Class variables belong to the class and are shared; instance variables belong to each object and are independent. The shadowing behavior when assigning through an instance is the single most important gotcha to remember, and the rule of always accessing class variables through the class name when modifying them prevents the most common mistakes.
More in this topic
Create Custom Iterators in Python
Learn how to build your own iterators in Python by implementing the __iter__() and __next__() methods, with practical examples and reusable patterns.
Python Iterator Protocol Explained
Learn how Python's iterator protocol works with the __iter__() and __next__() methods, and understand the contract every iterator must follow.
Python Iterables and Iterators Explained
Learn what iterables and iterators are in Python, how they power for loops under the hood, and why understanding them unlocks cleaner data processing patterns.