What is the difference between @classmethod, @staticmethod, and @property?
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.
| Aspect | @staticmethod | @classmethod | @property |
|---|---|---|---|
| First argument | None | cls (class) | self (instance) |
| Access to instance | No | No | Yes |
| Access to class | No (manually via name) | Yes | Via self.__class__ |
| Primary use case | Utility functions | Factory/alternative constructors | Computed/validated attributes |
| Inherited polymorphically | N/A | Yes (cls = subclass) | Yes |
| Called as | method() | method() | attribute access |
| Can be overridden in subclass | Yes | Yes (cls changes) | Yes |
Correctly explains what each decorator does (cls vs no arg vs attribute access) with at least one concrete use case per decorator.
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).
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