What you'll learn
- Tell the three kinds of method apart by what they receive:
self,cls, or nothing - Write alternative constructors with
@classmethod - Group helper functions with a class using
@staticmethod - Decide which kind a new method should be
Concept
Every method you have written so far is an instance method: it receives the object as self and works on that object's data. Two other kinds exist. A class method receives the class itself, conventionally named cls, and a static method receives nothing special at all. The decorator above the def tells Python which kind you mean: @classmethod or @staticmethod. Choosing between them comes down to one question: what does this method need to know about?
| Kind | Decorator | First parameter | Needs access to | Typical job |
|---|---|---|---|---|
| instance method | none | self |
this object's data | deposit, withdraw, describe |
| class method | @classmethod |
cls |
the class, not an instance | alternative constructors, registries |
| static method | @staticmethod |
none | neither | a helper that belongs nearby |
The most common use of a class method is an alternative constructor: a second way to build an instance. __init__ takes the raw pieces; Date.from_string("2026-09-08") or Account.from_dict(data) parses some other shape and then calls cls(...) with the pieces. Using cls rather than the class name means subclasses get the constructor for free and it builds the subclass, not the parent. Class methods also suit anything that reads or changes class-level state, like a counter of instances or a registry of known types.

A static method is a plain function that lives inside the class because it belongs with it conceptually: a validation rule, a unit conversion, a formatting helper. It cannot see self or cls, which is the point: it declares "I depend on nothing but my arguments". You could put the same function at module level; making it static keeps it next to the class it serves and lets you call it as Account.is_valid_iban(text).

Call any of the three through an instance or the class; the decorator decides what arrives. acct.from_dict(d) works but reads oddly; convention calls class and static methods on the class, Account.from_dict(d), so the reader knows no instance is involved.
Code
The three kinds side by side. Watch what each one receives when called on the class and on an instance.
# three_kinds.py
class Demo:
def instance(self):
return f"instance method got {type(self).__name__} object"
@classmethod
def klass(cls):
return f"class method got the class {cls.__name__}"
@staticmethod
def static():
return "static method got nothing special"
d = Demo()
print(d.instance())
print(d.klass())
print(Demo.klass())
print(Demo.static(), "|", d.static())
instance method got Demo object
class method got the class Demo
class method got the class Demo
static method got nothing special | static method got nothing specialAlternative constructors. Both class methods parse a different input shape and then call cls(...), so the real construction logic stays in one place.
# constructors.py
class Account:
def __init__(self, owner, balance):
self.owner = owner
self.balance = balance
def __repr__(self):
return f"Account({self.owner!r}, {self.balance})"
@classmethod
def from_dict(cls, data):
return cls(data["owner"], data.get("balance", 0))
@classmethod
def from_csv_row(cls, row):
owner, balance = row.split(",")
return cls(owner.strip(), float(balance))
print(Account("ada", 100))
print(Account.from_dict({"owner": "linus"}))
print(Account.from_csv_row("grace, 250.5"))
Account('ada', 100)
Account('linus', 0)
Account('grace', 250.5)Why cls and not the class name: a subclass calling the inherited constructor gets an instance of itself.
# cls_matters.py
class Account:
def __init__(self, owner, balance):
self.owner = owner
self.balance = balance
@classmethod
def from_dict(cls, data):
return cls(data["owner"], data["balance"])
class SavingsAccount(Account):
rate = 0.03
s = SavingsAccount.from_dict({"owner": "ada", "balance": 500})
print(type(s).__name__, s.rate, s.balance)
SavingsAccount 0.03 500Static methods as helpers, and a class method reading class-level state. The validator depends only on its argument; the counter depends on the class.
# helpers.py
class Account:
created = 0
def __init__(self, owner, iban):
if not self.is_valid_iban(iban):
raise ValueError(f"bad IBAN: {iban}")
self.owner = owner
self.iban = iban
Account.created += 1
@staticmethod
def is_valid_iban(text):
cleaned = text.replace(" ", "")
return cleaned[:2].isalpha() and cleaned[2:].isalnum() and 15 <= len(cleaned) <= 34
@classmethod
def how_many(cls):
return f"{cls.created} {cls.__name__} objects created"
print(Account.is_valid_iban("GB82 WEST 1234 5698 7654 32"))
print(Account.is_valid_iban("12345"))
Account("ada", "GB82 WEST 1234 5698 7654 32")
Account("linus", "DE89 3704 0044 0532 0130 00")
print(Account.how_many())
True
False
2 Account objects createdTry it yourself
Create temperature.py with a Temperature class storing degrees Celsius. Add a class method from_fahrenheit(f) and another from_kelvin(k), a static method is_plausible(celsius) that returns whether the value is above absolute zero, and an instance method describe(). Build one temperature each way, print the descriptions, and call the validator on the class with a valid and an impossible value.
Common mistakes
- Using the class name inside a class method.
return Account(...)instead ofcls(...)breaks subclasses, which get the parent type back. - Making everything static. If a function never touches
selforclsand has nothing to do with the class, it belongs at module level, not inside a class for tidiness. - Forgetting the decorator. A method without
@classmethodthat names its first parameterclsstill receives the instance; the decorator changes the behavior, not the name.
What's next
- Instance methods get
self, class methods getcls, static methods get nothing; the decorator decides. - Class methods are the home of alternative constructors and class-level state; call them on the class and build with
cls(...). - Static methods are helpers that belong with a class but need none of its data.
You now know every kind of method a class can have. Next you will build classes on top of other classes: inheritance and super().