Python OOP Tutorial 2: Class Variables
Based on Corey Schafer's video on YouTube. If you like this content, support the original creators by watching, liking and subscribing to their content.
Class variables are shared across all instances and are defined on the class (e.g., raise_amount, num_employees).
Briefing
Class variables let one shared value live on a class and be reused across every instance—perfect for data that should stay consistent company-wide, like an annual raise rate or a global employee counter. The tutorial contrasts this with instance variables, which store per-object data such as each employee’s name, email, and pay.
To make the difference concrete, the lesson starts with an Employee class that has an apply_raise method. Initially, the raise percentage is hard-coded inside apply_raise (pay multiplied by 1.04). That works, but it creates two problems: there’s no clean way to read the raise rate as employee.raise_amount, and updating the rate would require hunting through the code wherever the number appears. Moving the 4% value into a class variable (raise_amount = 1.04) fixes both issues—now the rate is defined once at the class level and can be accessed as either Employee.raise_amount or employee_instance.raise_amount.
The tutorial then digs into why instance access still works for class variables. When an attribute is requested on an instance, Python first checks the instance’s own namespace. If the attribute isn’t found there, Python falls back to the class (and its base classes). That’s why employee_instance.raise_amount returns the class’s raise_amount even though the instance itself doesn’t store that attribute. The lesson reinforces this by printing employee_instance.__dict__ (showing no raise_amount there) while also inspecting the class attribute via the class namespace.
A key nuance follows: assigning to a class variable through an instance can create an instance-specific override. When raise_amount is changed via employee_instance.raise_amount = 1.05, Python adds raise_amount to that instance’s namespace, so only that employee sees the new value; other instances still fall back to the original class value. This is why the tutorial recommends using self.raise_amount inside apply_raise: it allows per-instance overrides when needed, while still defaulting to the class value.
The lesson closes with a second class-variable example where self is less appropriate: tracking the total number of employees. A num_employees class variable starts at 0 and increments inside __init__ each time a new Employee instance is created. Accessing Employee.num_employees yields the shared count across all instances, and the increment happens reliably because __init__ runs for every instantiation.
Overall, the takeaway is practical: use instance variables for data unique to each object, use class variables for shared constants or global counters, and understand Python’s attribute lookup rules so you know when changes affect everyone versus only one instance.
Cornell Notes
Class variables store values shared across all instances of a class, while instance variables store per-object data. In the Employee example, moving a hard-coded raise percentage into a class variable (raise_amount) makes it readable as Employee.raise_amount or employee_instance.raise_amount and easier to update in one place. Python resolves attributes by first checking an instance’s namespace; if the attribute isn’t there, it falls back to the class. Assigning to a class variable through an instance creates an instance-specific override, so only that instance changes. The tutorial also uses a num_employees class variable incremented in __init__ to demonstrate a shared global counter across instances.
Why is a class variable better than hard-coding the raise percentage inside apply_raise?
How can an instance access a class variable if the instance doesn’t store it?
What happens when raise_amount is assigned through an instance (e.g., employee1.raise_amount = 1.05)?
Why does using self.raise_amount inside apply_raise matter?
When is it appropriate to use the class name instead of self for a class variable?
Review Questions
- What is the attribute lookup order in Python when accessing an attribute on an instance that may exist only on the class?
- How would you predict the behavior of apply_raise if one instance overrides raise_amount but others do not?
- Why does incrementing num_employees inside __init__ produce the correct shared total across multiple instances?
Key Points
- 1
Class variables are shared across all instances and are defined on the class (e.g., raise_amount, num_employees).
- 2
Instance variables hold data unique to each object (e.g., name, email, pay).
- 3
Python attribute access checks the instance namespace first; if missing, it falls back to the class namespace.
- 4
Reading a class variable through an instance works because of that fallback lookup behavior.
- 5
Assigning a class variable through an instance creates an instance-specific override that affects only that instance.
- 6
Using self.raise_amount inside methods lets per-instance overrides take effect while still defaulting to the class value.
- 7
Incrementing a class variable in __init__ is a reliable way to maintain a shared global counter across all instances.