Back to Blog
Python

Python classmethod vs staticmethod: Key Differences

python classmethod vs staticmethod: Understand the difference between Python classmethod and staticmethod, what each receives at call time, and how to choose the right...

classmethodstaticmethodPython decoratorsobject-oriented programminginheritance
Diagram showing a classmethod receiving the class object while a staticmethod receives no implicit argument, illustrating the Python decorator difference.

When you define a method inside a Python class, the @classmethod and @staticmethod decorators change what the method receives when it is called. The difference is simple at the syntax level but has real consequences for inheritance, factory methods, and how much state the method can access. Understanding python classmethod vs staticmethod comes down to one question: does the method need the class itself, or does it need nothing at all?

The Syntax Difference Between classmethod and staticmethod

class Order: tax_rate = 0.08 def __init__(self, items): self.items = items @classmethod def from_quantity(cls, item_price, quantity): return cls([item_price] * quantity) @staticmethod def format_price(value): return f"${value:.2f}"

A classmethod receives the class as its first argument, conventionally named cls. A staticmethod receives no implicit first argument at all. The instance method __init__ receives the instance as self.

When you call Order.from_quantity(10, 3), Python passes Order as cls. When you call Order.format_price(10), Python passes only 10; the method behaves like a plain function that happens to live inside the class body.

What cls Actually Is and Why It Matters

The cls argument is not a fixed reference to the class where the method was defined. It is the class that the method was called on. That distinction becomes visible with inheritance:

class DiscountedOrder(Order): discount = 0.1 def total(self): return sum(self.items) * (1 - self.discount)

Calling DiscountedOrder.from_quantity(10, 3) passes DiscountedOrder as cls, so the factory creates a DiscountedOrder instance. If the method had been written as a staticmethod returning Order(...), the subclass would never be used.

This is the main reason classmethods exist: they let a factory or alternative constructor build the correct class even when called through a subclass.

A staticmethod has no such awareness. DiscountedOrder.format_price(10) runs the same function with no reference to DiscountedOrder. If the formatting logic ever needed to depend on class-level configuration, a staticmethod would be the wrong choice.

Using classmethod for Alternative Constructors

The most common use of classmethod is an alternative constructor. Python's built-in dict.fromkeys is a classmethod: it creates a dict from an iterable of keys. The pattern is the same in your own classes.

class Temperature: def __init__(self, celsius): self.celsius = celsius @classmethod def from_fahrenheit(cls, fahrenheit): return cls((fahrenheit - 32) * 5 / 9)

Temperature.from_fahrenheit(212) creates a Temperature instance with celsius == 100.0. The factory converts the input format and delegates construction to cls, so any subclass of Temperature that calls from_fahrenheit receives an instance of that subclass.

The alternative—a staticmethod that returns Temperature(...)—would hard-code the base class and break subclass behavior.

Using staticmethod for Namespaced Utility Functions

A staticmethod is appropriate when the function is conceptually tied to the class but does not need class or instance state. Formatting, validation, and conversion helpers are typical candidates.

class Order: def __init__(self, items): self.items = items @staticmethod def format_price(value): return f"${value:.2f}"

Order.format_price(19.5) returns "$19.50". The method does not read self or cls. It exists inside the Order namespace so that callers can find it next to the class that uses it.

A staticmethod can always be moved to a module-level function without changing its behavior. Keeping it in the class is a namespacing decision. If the helper is only used by one class, placing it as a staticmethod keeps the module namespace cleaner. If the helper is shared across many classes, a module-level function is usually better.

Runtime Behavior: What Python Passes to Each

The decorators change how the descriptor protocol binds the function to the class or instance.

  • A plain method is bound to the instance: calling order.total() passes order as self.
  • A classmethod is bound to the class: calling Order.from_quantity(...) or order.from_quantity(...) passes the class as cls.
  • A staticmethod is not bound at all: calling Order.format_price(...) or order.format_price(...) passes only the explicit arguments.

Note that a classmethod can be called on an instance too. order.from_quantity(10, 3) still receives Order as cls, not order. The instance is ignored. This is a common source of confusion, but the behavior is consistent: classmethods always receive the class, never the instance.

Choosing Between classmethod and staticmethod

Use a classmethod when the method needs to:

  • create an instance of the class, especially through a subclass
  • read or modify class-level attributes
  • provide an alternative constructor

Use a staticmethod when the method:

  • does not need class or instance state
  • is a pure function of its arguments
  • exists in the class namespace only for organizational reasons

The decision usually comes down to whether the method would behave differently if called through a subclass. If it would, use classmethod. If it would not, staticmethod is sufficient and simpler.

A common mistake is reaching for staticmethod for an alternative constructor. That works until a subclass needs the same factory, at which point the hard-coded base class reference becomes a bug. Writing the factory as a classmethod from the start avoids that failure mode.

python classmethod vs staticmethod: Practical Usage and Code | RYUSLOG DEV