Lesson 7 · OKSTEM College · Associate of Science in Computer Science
Class Variables vs Instance Variables
An instance variable is unique to each object (self.x). A class variable is shared across all instances — defined directly in the class body.
classCounter:
count = 0# class variable — shareddef__init__(self, name):
self.name = name # instance variableCounter.count += 1# modify via class name, not self
a = Counter("Alice")
b = Counter("Bob")
print(Counter.count) # 2 (both objects share the class variable)
Gotcha: Writing self.count += 1 creates a new instance variable on that object instead of updating the class variable. Always use ClassName.var to modify shared state.
@staticmethod
A static method belongs to the class namespace but receives neither self nor cls. Use it for utility functions that relate to the class but don't need instance or class state.
classMathUtils:
@staticmethoddefclamp(value, lo, hi):
returnmax(lo, min(hi, value))
@staticmethoddefis_prime(n):
if n < 2: returnFalsereturnall(n % i != 0for i inrange(2, int(n**0.5)+1))
print(MathUtils.clamp(150, 0, 100)) # 100print(MathUtils.is_prime(17)) # True
@classmethod — Alternative Constructors
A class method receives the class itself as cls. The most common use is providing alternative constructors (factory methods).
classDate:
def__init__(self, year, month, day):
self.year=year; self.month=month; self.day=day
@classmethoddeffrom_string(cls, date_str: str):
"""Alternate constructor: Date.from_string('2025-08-15')"""
y, m, d = (int(x) for x in date_str.split('-'))
returncls(y, m, d)
def__repr__(self):
returnf"Date({self.year}, {self.month}, {self.day})"
d = Date.from_string("2025-08-15")
print(d) # Date(2025, 8, 15)
Practice Problems
1. What is the difference between @staticmethod and @classmethod?
@staticmethod: no implicit first argument.
Use for pure utility functions that don't touch class or instance state.
@classmethod: receives cls as first argument (the class itself).
Use for factory methods / alternative constructors that need to
create instances of the class (or a subclass if inherited).
2. Add a today() classmethod to Date using datetime.date.today().
Correct — written at class level, outside any method.
Class variables can be public or protected.
Shared mutable state requires explicit locking in threaded code.
Recap: class variable = defined in class body (not inside a method). Shared by every instance. Modify via ClassName.var, not self.var.
Writing self.count += 1 when count is a class variable
self.count += 1 creates a NEW instance variable, shadowing the class one.
Correct — use ClassName.count += 1 to modify the shared value.
Python allows it — but silently creates an instance attribute.
No deletion; the class variable still exists on the class object.
Recap: self.count += 1 is shorthand for self.count = self.count + 1 — which creates a new instance attribute. Use ClassName.count += 1 for shared state.
A @staticmethod is appropriate when
Use a regular method (with self) for that.
Correct — utility functions like validators or converters are good candidates.
Use @classmethod for factory/constructor patterns.
Both static and class methods are inherited.
Recap: static methods are like regular module functions, just namespaced inside a class. No self, no cls.
The first parameter of a @classmethod is named
self is for instance methods; cls is for class methods.
Correct — cls receives the class itself, not an instance.
klass is sometimes used informally, but cls is the universal convention.
type is a built-in; cls is the correct parameter name.
Recap: @classmethod def from_string(cls, ...) — cls is the class. Calling cls(...) creates an instance, which works correctly even in subclasses.
Alternative constructors are best implemented as
Hardcoding the class name breaks subclass inheritance.
Correct — cls(...) creates an instance of whatever class called the method.
Python doesn't support method overloading — each class has one __init__.
Module functions work but aren't discoverable through the class interface.
Recap: Date.from_string('2025-08-15') uses cls so that SpecialDate.from_string(...) returns a SpecialDate, not a Date.