Class vs Instance vs Static Methods
Python offers three method flavors. Instance methods operate on objects, class methods on the class (often factories), and static methods as namespaced functions without implicit self or cls.
Recipe
class User:
def __init__(self, email: str) -> None:
self.email = email
def domain(self) -> str:
return self.email.split("@", 1)[1]
@classmethod
def from_row(cls, row: dict[str, str]) -> "User":
return cls(row["email"])
@staticmethod
def is_valid_email(email: str) -> bool:
return "@" in email and "." in email.split("@", 1)[-1]When to reach for this:
- Alternative constructors (
from_json,from_env) - Utilities logically grouped with class but not needing state
- Inherited factory methods respecting subclass
cls - Enum/custom class methods modifying class state
Working Example
from datetime import datetime, timezone
class Event:
def __init__(self, name: str, ts: datetime) -> None:
self.name = name
self.ts = ts
def age_seconds(self, now: datetime | None = None) -> float:
now = now or datetime.now(timezone.utc)
return (now - self.ts).total_seconds()
@classmethod
def now(cls, name: str) -> "Event":
return cls(name, datetime.now(timezone.utc))
@classmethod
def from_iso(cls, name: str, iso: str) -> "Event":
ts = datetime.fromisoformat(iso.replace("Z", "+00:00"))
return cls(name, ts)
@staticmethod
def normalize_name(name: str) -> str:
return name.strip().lower()
class AdminEvent(Event):
pass
if __name__ == "__main__":
base = Event.now("deploy")
admin = AdminEvent.now("promote")
print(type(base), type(admin))
print(Event.is_valid_email("a@b.com"))What this demonstrates:
nowclassmethod is alternative constructorAdminEvent.nowreturnsAdminEventbecauseclsis subclassage_secondsinstance method uses object statenormalize_namestaticmethod needs neither self nor cls
Deep Dive
How It Works
- Bound methods - Instance methods bind
selfat call time. - classmethod descriptor - Passes class as first argument automatically.
- staticmethod descriptor - No automatic first argument.
- Inheritance -
clsin classmethod is actual class called (AdminEventnotEvent). - Access - Classmethods can touch class attributes; instance methods instance attrs.
When to Use Which
| Decorator | First arg | Typical use |
|---|---|---|
| (none) | self | Object behavior |
@classmethod | cls | Factories, class config |
@staticmethod | none | Grouped helper |
Python Notes
# enum-style classmethod pattern
class Money:
def __init__(self, amount: int, currency: str) -> None:
self.amount = amount
self.currency = currency
@classmethod
def usd(cls, amount: int) -> "Money":
return cls(amount, "USD")Gotchas
- staticmethod when classmethod needed - Factory returning
clsbreaks on subclasses with staticmethod. Fix: Use classmethod for polymorphic constructors. - classmethod accessing instance state - No
selfavailable. Fix: Pass instance explicitly or use instance method. - Confusing module-level function - staticmethod that never touches class - could be module function. Fix: staticmethod only when grouping API on class namespace.
- Abstract classmethod order - Stack
@classmethodand@abstractmethodper Python version docs. - Calling classmethod on instance - Allowed but unusual - still passes real class.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Module function | No class grouping needed | API belongs with class |
__init__ only | Single construction path | Multiple parsing sources |
Pydantic model_validate | Validated DTO parsing | Non-pydantic domain |
dataclass __post_init__ | Post-construct validation | Alternate constructors |
FAQs
classmethod vs __init__?
Use classmethod factories when multiple construction paths parse different inputs into same type.
Why AdminEvent.now returns AdminEvent?
cls bound to class used in call - polymorphic factory behavior.
staticmethod on instance?
Callable from instance but ignores it - no state access.
classmethod for decorators?
Rare - some registry patterns register subclasses via __init_subclass__ instead.
typing classmethod?
Return Self (3.11+) from classmethods for correct subclass typing.
classmethod property?
Python 3.9+ classmethod wrapping property patterns exist for metaprogramming - advanced.
staticmethod inheritance?
Inherited unchanged - still no cls binding on subclass unless overridden.
alternative constructor naming?
from_json, from_env, parse conventions - not __init__ overloads.
classmethod mutating class state?
Possible via cls._registry patterns - document thread safety if shared mutable class state.
fastapi dependency factories?
Often plain functions - classmethods when factory tied to service class configuration.
Related
- Properties & Descriptors - method descriptors
- dataclasses - construction patterns
- Inheritance & MRO - cls in MRO context
- Enums - enum class methods
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.