classmethod
staticmethod
python

What is the difference between @staticmethod and @classmethod in Python?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

@staticmethod and @classmethod both define methods on a class, but they receive different context and solve different design problems. staticmethod behaves like a namespaced utility function, while classmethod receives the class object and is often used for alternate constructors or class-level behavior. Choosing correctly keeps APIs extensible and inheritance-friendly.

Core Binding Difference

A normal instance method receives self. The two decorators change that binding:

  • @staticmethod receives no automatic first argument.
  • @classmethod receives cls as first argument.
python
1class Demo:
2    @staticmethod
3    def s(x):
4        return x * 2
5
6    @classmethod
7    def c(cls, x):
8        return cls.__name__, x * 2
9
10
11print(Demo.s(3))
12print(Demo.c(3))

This binding difference drives most design decisions.

When to Use @staticmethod

Use static methods when logic belongs conceptually to class domain but does not need class or instance state.

python
1class MathUtils:
2    @staticmethod
3    def clamp(value: float, low: float, high: float) -> float:
4        return max(low, min(high, value))
5
6
7print(MathUtils.clamp(12, 0, 10))

This could be a module-level function too. staticmethod is mainly an organizational choice.

Good static method traits:

  • pure utility logic
  • no dependency on mutable class variables
  • no need for subclass-specific behavior

When to Use @classmethod

Use class methods when behavior should vary with subclass or when constructing class instances from alternative inputs.

python
1class User:
2    def __init__(self, name: str, email: str):
3        self.name = name
4        self.email = email
5
6    @classmethod
7    def from_csv(cls, line: str):
8        name, email = line.strip().split(",")
9        return cls(name=name, email=email)
10
11
12u = User.from_csv("Ava,[email protected]")
13print(u.name, u.email)

Because method calls cls(...), subclasses automatically get correct instance type when they inherit this constructor.

Inheritance Behavior Difference

Inheritance highlights why class methods are powerful.

python
1class Animal:
2    kind = "animal"
3
4    @classmethod
5    def create(cls, name: str):
6        obj = cls()
7        obj.name = name
8        return obj
9
10
11class Dog(Animal):
12    kind = "dog"
13
14
15a = Animal.create("generic")
16d = Dog.create("milo")
17
18print(type(a).__name__, a.kind)
19print(type(d).__name__, d.kind)

Dog.create produces Dog instance because cls refers to subclass at call time.

A static method cannot do this automatically unless subclass type is passed manually.

Practical API Design Patterns

Common classmethod patterns:

  • alternate constructors from JSON, CSV, environment, or DB row
  • class-level caches or registries
  • factory behavior requiring subclass-aware dispatch

Common staticmethod patterns:

  • validation helpers
  • deterministic text formatting
  • small conversion utilities near model code

If method reads or mutates class state, classmethod is usually the right choice.

Interaction with Dataclasses and Validation

In dataclass-heavy code, class methods are often used for richer construction flows.

python
1from dataclasses import dataclass
2
3
4@dataclass
5class Config:
6    host: str
7    port: int
8
9    @classmethod
10    def from_env(cls, env: dict):
11        return cls(
12            host=env.get("APP_HOST", "localhost"),
13            port=int(env.get("APP_PORT", "8080")),
14        )
15
16    @staticmethod
17    def validate_port(port: int) -> bool:
18        return 1 <= port <= 65535
19
20
21cfg = Config.from_env({"APP_HOST": "127.0.0.1", "APP_PORT": "9000"})
22print(cfg)
23print(Config.validate_port(cfg.port))

This separation keeps construction and validation concerns clear.

Testing and Mocking Considerations

Both method types are easy to test, but semantics differ:

  • static methods are usually pure and isolated
  • class methods may depend on class attributes or subclass overrides

When refactoring, class methods preserve polymorphism better than static methods in inheritance-heavy designs.

Common Pitfalls

A common pitfall is using staticmethod for alternate constructors, which blocks subclass-friendly instantiation. Another is using classmethod for utility logic that never touches class state, adding unnecessary complexity. Teams also sometimes convert module-level functions into static methods only for style consistency, reducing reuse across modules. Finally, unclear method intent can confuse API users who expect instance behavior from class-level methods.

Summary

  • @staticmethod has no automatic self or cls binding.
  • @classmethod receives cls and supports subclass-aware behavior.
  • Use static methods for utility logic independent of class state.
  • Use class methods for alternate constructors and class-level workflows.
  • Choose based on semantic intent, not decorator popularity.

Course illustration
Course illustration

All Rights Reserved.