Class Variables vs Instance Variables
What's shared by the class and what belongs to each object
In this lesson
Explain it like I’m 5
An instance variable is your own backpack — only you carry it. A class variable is the classroom shelf everyone can reach. Change your backpack and nobody else is affected; change the shelf and everyone sees it.
One per object vs shared by all
An instance variable is created on self inside __init__, so each object gets its own copy. A class variable is defined directly in the class body, outside any method, and is shared by every object and by the class itself. Use a class variable for something genuinely common, like a school name or a game title.
class Student:
school = "PyLI5 Academy" # shared by every student
def __init__(self, name):
self.name = name # unique to each student
a = Student("Ada")
b = Student("Bo")
print(a.name, "-", a.school)
print(b.name, "-", b.school)
Ada - PyLI5 Academy Bo - PyLI5 Academy
The mutable class-variable trap
The danger appears when a class variable is a mutable object like a list or dict. Because every object shares the one list, appending through one object changes it for all of them. Almost always, per-object data belongs on self in __init__ instead.
class Cart:
items = [] # BUG: one list shared by every cart
def add(self, thing):
self.items.append(thing)
a = Cart()
b = Cart()
a.add("apple")
print(b.items) # b sees a's item!
['apple']
class Cart:
def __init__(self):
self.items = [] # each cart gets its OWN list
def add(self, thing):
self.items.append(thing)
a = Cart()
b = Cart()
a.add("apple")
print(b.items)
[]
Common mistake: Using a mutable class variable for per-object data
Writing items = [] in the class body looks like a neat default, but it makes one list shared by every object.
Create per-object collections in __init__ with self.items = [] so each object gets its own.
Common mistake: Changing a class variable when you meant to change one object
Assigning to self.school versus ClassName.school behaves differently, and the difference is easy to miss.
To change the shared value for everyone, assign through the class (Student.school = ...). Assigning self.school = ... instead creates a new instance variable that shadows the shared one for just that object.
In the Student example, which value is shared by every object?
school is defined in the class body, so every student shares it; name is set per object in __init__.
Why is items = [] at class level dangerous for per-user carts?
A single shared list means appending through one object changes it for all of them.
Where should data that differs per object be created?
Per-object data belongs on self in __init__, so each object gets its own copy.
Mini exercise (medium)
Create a Player class with a shared game_name class variable and a per-player score that starts at 0. Add an add_points(points) method that increases this player’s score. Make two players, give them different points, and confirm their scores are separate.
Do it here. Finish the code below and press Run to try your answer right in the browser — no setup needed.
class Player:
game_name = "Space Blasters" # shared by all players
def __init__(self, name):
self.name = name
# TODO: give each player their own score, starting at 0
def add_points(self, points):
# TODO: add points to this player's score
pass
p1 = Player("Ada")
p2 = Player("Bo")
p1.add_points(10)
p2.add_points(3)
print(p1.name, p1.score, "in", p1.game_name)
print(p2.name, p2.score, "in", p2.game_name)
Put game_name = "..." in the class body, set self.score = 0 in __init__, and do self.score += points in the method.
class Player:
game_name = "Space Blasters"
def __init__(self, name):
self.name = name
self.score = 0
def add_points(self, points):
self.score += points
p1 = Player("Ada")
p2 = Player("Bo")
p1.add_points(10)
p2.add_points(3)
print(p1.name, p1.score, "in", p1.game_name)
print(p2.name, p2.score, "in", p2.game_name)
Ada 10 in Space Blasters
Bo 3 in Space Blasters
assert p1.score == 10 and p2.score == 3, "each player should keep their own score"
assert Player.game_name == "Space Blasters", "game_name should stay a shared class variable"
assert "score" not in Player.__dict__, "score should be set on self in __init__, not as a class variable"
print("✓ Shared name, separate scores!")