Class and Static Methods Checkpoint
25 min · Intermediate
Need help? Ask a tutor on WhatsApp (opens in a new tab)Fix the mistakes
The slips that cost marks in this module. Spot each one, then check the fix.
A real class uses all three method types, each for a different job. This checkpoint builds one small design and then tests your choices.
Decide the job of each method
For every piece of logic, ask what it needs. A subscription has a plan and a seat count. Its monthly total needs both, so it is an instance method.
Building from "PRO-5" needs the class only. Checking a plan name needs nothing.
Example 1 · One design, three method types
class Subscription: PRICES = {"BASIC": 500, "PRO": 1200}
def __init__(self, plan, seats): if not Subscription.is_valid_plan(plan): raise ValueError("unknown plan") if seats < 1: raise ValueError("seats must be at least 1") self.plan = plan self.seats = seats
@classmethod def from_code(cls, code): plan, seats = code.split("-") return cls(plan, int(seats))
@staticmethod def is_valid_plan(plan): return plan in Subscription.PRICES
def monthly_total(self): return Subscription.PRICES[self.plan] * self.seats
sub = Subscription.from_code("PRO-5")print(sub.plan, sub.seats, sub.monthly_total())print(Subscription.is_valid_plan("TRIAL"))PRO 5 6000 False
What this code does
from_codesplits the text and callscls.monthly_totalusesselfdata.is_valid_planneeds neither.
Example 2 · One class, three kinds of method
class Subscription: PRICES = {"BASIC": 500, "PRO": 1200}
def __init__(self, plan, seats): if not Subscription.is_valid_plan(plan): raise ValueError("unknown plan") if seats < 1: raise ValueError("seats must be at least 1") self.plan = plan self.seats = seats
@classmethod def from_code(cls, code): plan, seats = code.split("-") return cls(plan, int(seats))
@staticmethod def is_valid_plan(plan): return plan in Subscription.PRICES
def monthly_total(self): return Subscription.PRICES[self.plan] * self.seats
team = Subscription.from_code("PRO-3")print(team.monthly_total())print(Subscription.is_valid_plan("GOLD"))3600 False
What this code does
from_codeneeds the class to build an object, so it is a class method.is_valid_planneeds neither the class nor an object, so it is a static method.monthly_totalreads this object's plan and seats, so it is an instance method.
Each method uses the least it needs: self, cls, or nothing. A reader can tell from the signature what a method can touch.
Keep the rules in one place
The factory calls cls(...), and __init__ checks the plan with the static helper. Every route to a subscription goes through the same two checks.
sub = Subscription.from_code("PRO-5")print(sub.monthly_total())Example 3 · Both routes are checked
class Subscription: PRICES = {"BASIC": 500, "PRO": 1200}
def __init__(self, plan, seats): if not Subscription.is_valid_plan(plan): raise ValueError("unknown plan") if seats < 1: raise ValueError("seats must be at least 1") self.plan = plan self.seats = seats
@classmethod def from_code(cls, code): plan, seats = code.split("-") return cls(plan, int(seats))
@staticmethod def is_valid_plan(plan): return plan in Subscription.PRICES
def monthly_total(self): return Subscription.PRICES[self.plan] * self.seats
for build in (lambda: Subscription("GOLD", 2), lambda: Subscription.from_code("BASIC-0")): try: build() except ValueError as error: print("Rejected:", error)Rejected: unknown plan Rejected: seats must be at least 1
What this code does
- The direct call fails on the plan, the factory call fails on the seat count.
- Both errors come from
__init__, so the rules cannot be skipped.
Bad input fails in one place with one message, whichever way the object is built.
Questions to ask in any design
Before adding a helper to a class, check these. If the helper is used by several unrelated classes, make it a plain function. If subclasses may change the data it uses, make it a class method. If it reads one object's data, make it an instance method.
Example 4 · A subclass keeps its type
class Subscription: PRICES = {"BASIC": 500, "PRO": 1200}
def __init__(self, plan, seats): if not Subscription.is_valid_plan(plan): raise ValueError("unknown plan") if seats < 1: raise ValueError("seats must be at least 1") self.plan = plan self.seats = seats
@classmethod def from_code(cls, code): plan, seats = code.split("-") return cls(plan, int(seats))
@staticmethod def is_valid_plan(plan): return plan in Subscription.PRICES
def monthly_total(self): return Subscription.PRICES[self.plan] * self.seats
class TeamSubscription(Subscription): pass
team = TeamSubscription.from_code("BASIC-10")print(type(team).__name__, team.monthly_total())TeamSubscription 5000
What this code does
from_codeis inherited and usescls, so it builds aTeamSubscription.- 10 seats at 500 each give 5000.
Finish up
Mark complete & continue
Next: Single Inheritance and Method Overriding