Python Built-in Method Decorators
Python's built-in method decorators control whether methods receive an instance or class automatically, or expose method logic through attribute access. Knowing their binding behavior helps choose clear APIs and support subclassing.
These built-in decorators change how a function in a class body is exposed. They are commonly useful for making the intended relationship between an operation and its class explicit.
A regular instance method is bound to an instance: calling `obj.method(x)` passes `obj` as the first argument. `@staticmethod` prevents that automatic binding. The function can be called through the class or an instance, but receives only the arguments explicitly supplied.
`@classmethod` creates a method bound to the class. Its first parameter, conventionally named `cls`, is the class through which the method was accessed. This is useful for alternate constructors and operations that need to work with subclasses.
`@property` exposes a method as a read-only attribute by default, so callers write `obj.value` rather than `obj.value()`. A property can also have a setter or deleter, and is implemented using Python's descriptor machinery. These decorators are separate from context-manager support; context managers typically use `with` and implement methods such as `__enter__` and `__exit__`.
Key points
- Use an instance method when behavior needs per-object state.
- Use `@staticmethod` when no implicit instance or class is needed.
- Use `@classmethod` when behavior needs the class, often for alternate construction.
- Use `@property` for controlled or computed attribute access.
- Properties and methods rely on Python's descriptor and binding behavior.
Interview questions
How do instance methods, static methods, and class methods differ?
A regular instance method is bound to an object, so Python supplies that object as the first argument. A static method does not receive an implicit first argument. A class method receives the accessing class as its first argument, conventionally called `cls`. Choose based on whether the operation needs instance state, class-level behavior, or neither.
Why is `@classmethod` often used for alternate constructors?
A class method can serve as an alternate constructor because it receives the class in `cls` and can return `cls(...)`. If inherited and called through a subclass, `cls` refers to that subclass, so the factory can construct the right type without hard-coding the base class name. A static method has no such class argument, so it would need the class named explicitly or passed in.
What is a property, and when should you use one?
A property is a descriptor that allows method logic to be accessed using attribute syntax. Its getter is invoked when the attribute is read, and a setter or deleter can be provided to control writes or deletion. This can preserve a public attribute interface while adding validation or computed behavior. It should generally remain inexpensive and unsurprising because callers may not realize that code runs on access.
What happens when you assign to a property without a setter?
For a standard `property`, the getter is invoked on attribute read, and the setter is invoked on assignment if one is defined. Without a setter, assignment through that property normally fails rather than replacing the computed value. A property is therefore useful for enforcing invariants or deriving a value while keeping attribute-style access. It is not a general replacement for methods when an operation has substantial work or side effects.
How do these decorators relate to descriptors and attribute lookup?
Decorators are applied when the class body is executed, and their results become the attributes stored on the class. For example, `@classmethod` wraps the function in a descriptor that binds the class when accessed. `@staticmethod` similarly prevents receiver binding, while `property` creates a property descriptor. This descriptor-based behavior explains why access through an instance or class can produce different results.