How does @property work as a getter, setter, and deleter?
Python's `@property` decorator turns a method into a descriptor that's accessed like an attribute — `obj.name` instead of `obj.name()`. This lets you expose a clean attribute interface while executing code (validation, computation, lazy loading) on access or assignment.
The getter is defined with `@property`. It runs when the attribute is read: `obj.temperature`. If you only define a getter, the attribute is read-only — attempting to assign raises `AttributeError: can't set attribute`.
The setter is defined with `@temperature.setter` (using the property's name). It runs when the attribute is assigned: `obj.temperature = 37`. The setter receives the new value as an argument. This is where you typically validate: raise `ValueError` for out-of-range values, coerce types, or trigger side effects like invalidating a cache.
The deleter is defined with `@temperature.deleter`. It runs when `del obj.temperature` is executed. Less commonly needed, but useful for releasing resources, clearing cached values, or resetting to a default state.
The full pattern in practice: ```python class Circle: def __init__(self, radius): self._radius = radius # underscore: internal storage
@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
@radius.deleter def radius(self): del self._radius ```
A critical point: the property and its setter/deleter must share the same name. The decorator syntax `@radius.setter` works because `@property` returns a property object with `.setter()`, `.getter()`, and `.deleter()` methods that return new property objects with the respective accessor replaced.
The key design benefit: you can start with a plain attribute, then refactor to a property with validation later — all callers continue to use `obj.radius` unchanged. This is why Pythonistas don't write getters and setters upfront like in Java — you pay the property cost only when you need it.
Properties are implemented as descriptors, which is the broader protocol Python uses for attribute access control (`__get__`, `__set__`, `__delete__`). `property` is a built-in descriptor class.
Correctly explains getter, setter, and deleter syntax and when each runs, explains the private attribute convention (_name), and articulates the design benefit (uniform attribute interface with controlled access).
All of the above plus: explains why properties allow deferring validation to when it's needed (start with plain attribute, refactor later), mentions the descriptor protocol underneath, and explains the mechanism by which @radius.setter works (property object's .setter() method).
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