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.
Search across all documentation pages
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.
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:
from_json, from_env)clsfrom 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:
now classmethod is alternative constructorAdminEvent.now returns AdminEvent because cls is subclassage_seconds instance method uses object statenormalize_name staticmethod needs neither self nor clsself at call time.cls in classmethod is actual class called (AdminEvent not Event).| Decorator | First arg | Typical use |
|---|---|---|
| (none) | self | Object behavior |
@classmethod | cls | Factories, class config |
@staticmethod | none | Grouped helper |
# 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")cls breaks on subclasses with staticmethod. Fix: Use classmethod for polymorphic constructors.self available. Fix: Pass instance explicitly or use instance method.@classmethod and @abstractmethod per Python version docs.| 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 |
Use classmethod factories when multiple construction paths parse different inputs into same type.
cls bound to class used in call - polymorphic factory behavior.
Callable from instance but ignores it - no state access.
Rare - some registry patterns register subclasses via __init_subclass__ instead.
Return Self (3.11+) from classmethods for correct subclass typing.
Python 3.9+ classmethod wrapping property patterns exist for metaprogramming - advanced.
Inherited unchanged - still no cls binding on subclass unless overridden.
from_json, from_env, parse conventions - not __init__ overloads.
Possible via cls._registry patterns - document thread safety if shared mutable class state.
Often plain functions - classmethods when factory tied to service class configuration.
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+.
Reviewed by Chris St. John·Last updated Jul 19, 2026