← Back to Python

@classmethod vs @staticmethod vs @property

PythonMidpython

The Question

What is the difference between @classmethod, @staticmethod, and @property?

What a Strong Answer Covers

  • classmethod gets cls
  • "staticmethod gets neither
  • "classmethod for alt constructors

Senior-Level Answer

These three decorators are distinct tools that change how a method receives arguments and how it is invoked — understanding them requires understanding Python's descriptor protocol.

**@staticmethod** is the simplest. It converts a function so that it receives no implicit first argument. The method is logically grouped inside the class for organizational purposes but has no access to the instance or the class. Use it for pure utility functions that conceptually belong with the class but don't need class or instance state.

```python class MathUtils: @staticmethod def clamp(value, low, high): return max(low, min(value, high)) ```

**@classmethod** passes the class itself (`cls`) as the first argument instead of the instance. It is inherited polymorphically — `cls` refers to the actual subclass when called on a subclass, not the class where the method is defined. The primary use case is alternative constructors (factory methods):

```python class Date: @classmethod def from_string(cls, s): year, month, day = map(int, s.split('-')) return cls(year, month, day) # respects subclassing ```

Other uses: accessing or modifying class-level state, and registry patterns.

**@property** makes a method callable like an attribute. It implements the descriptor protocol with `__get__`, `__set__`, and `__delete__` hooks via `.setter` and `.deleter` sub-decorators. Properties enforce encapsulation: expose a clean attribute interface while hiding implementation, validate on assignment, or compute derived values lazily:

```python class Circle: def __init__(self, radius): self._radius = radius

@property def radius(self): return self._radius

@radius.setter def radius(self, value): if value < 0: raise ValueError('Radius must be non-negative') self._radius = value

@property def area(self): return 3.14159 * self._radius ** 2 ```

Key distinction: `@classmethod` and `@staticmethod` are about argument passing; `@property` is about attribute access semantics. You can combine `@classmethod` with `@property` in Python 3.9+ (deprecated in 3.13 in favor of explicit descriptors), but this is rarely necessary.

In interviews, ground your answer in a concrete use case for each rather than an abstract description.

Key Differences

Aspect@staticmethod@classmethod@property
First argumentNonecls (class)self (instance)
Access to instanceNoNoYes
Access to classNo (manually via name)YesVia self.__class__
Primary use caseUtility functionsFactory/alternative constructorsComputed/validated attributes
Inherited polymorphicallyN/AYes (cls = subclass)Yes
Called asmethod()method()attribute access
Can be overridden in subclassYesYes (cls changes)Yes

What Separates a 2/3 from a 3/3

2/3 — Passing but Incomplete

Correctly explains what each decorator does (cls vs no arg vs attribute access) with at least one concrete use case per decorator.

3/3 — Strong Answer

Covers argument passing mechanics, explains classmethod polymorphism with subclassing, property getter/setter pattern, and can discuss when not to use property (simple attributes don't need it).

Common Mistakes

  • Saying staticmethod 'can't access the class' but forgetting to explain why classmethod is preferred over staticmethod for factories
  • Using @property for every attribute as 'best practice' — simple public attributes don't need it
  • Confusing @classmethod with metaclass methods
  • Not knowing that cls in classmethod refers to the actual subclass, not the defining class

Follow-Up Questions

  • Why use @classmethod instead of @staticmethod for a factory method? — cls in classmethod refers to the subclass when called on a subclass, so the factory returns the correct type without hardcoding the class name.
  • When would you NOT use @property? — When the computation is expensive and surprising (property looks like attribute access — O(1) expected); use an explicit method instead.
  • How does the descriptor protocol relate to @property? — @property returns a descriptor object. __get__ is called on attribute read, __set__ on write. This is the same protocol __slots__ uses.
  • Can you make a classmethod that also acts as a property? — Chaining @classmethod and @property worked in 3.9-3.12 but was deprecated. Explicit descriptor classes are the correct approach.

Related Questions

  • GIL — What It Is and What It Protects
  • ThreadPoolExecutor & ProcessPoolExecutor
  • Decorators — Under the Hood
  • Generators & yield
  • Context Managers

Can You Explain This Cold?

Reading the answer is step one. Explaining it unprompted — under interview pressure — is what actually matters. Get AI-graded feedback on your answer with follow-up probes on your weak points.

Get Graded — Free Assessment
GrindQuestionsAITechnical interview assessment
TermsPrivacyAbout