Property Decorator
The Property Decorator in Python: Advanced Patterns & Descriptors
The @property decorator is one of Python's most elegant mechanisms for managing object state. It allows methods to be accessed syntactically as simple attributes (user.email) while executing getter, setter, and deleter logic behind the scenes. In advanced Python architecture, properties provide data encapsulation, lazy caching, and transparent backward compatibility.
1. How @property Works Under the Hood
The @property decorator is implemented as a built-in Python Descriptor class. Under the hood, decorating a method with @property creates an instance of the property class:
Using decorator syntax (@property, @attr.setter, @attr.deleter) is clean syntactic sugar that progressively populates fget, fset, and fdel.
2. Complete Lifecycle: Getter, Setter, and Deleter
3. Computed & Derived Properties
Properties eliminate redundant stored state. Instead of storing first_name, last_name, and full_name (which risks synchronization bugs when names change), compute derived values dynamically on access:
4. Lazy Evaluation with functools.cached_property
When a property involves expensive I/O operations (reading files, calling remote APIs, running neural network inferences), recalculating it on every read degrades performance.
Introduced in Python 3.8, functools.cached_property computes the value once upon first access, stores the result in the instance's __dict__, and serves subsequent accesses directly from cache with zero overhead:
5. Critical Pitfalls: The Recursion Trap
self.celsius = value). That calls the setter again recursively, resulting in a fatal RecursionError: maximum recursion depth exceeded!
Always assign to a private/protected backing attribute (e.g., self._celsius = value).Multiple Choice Questions
1. What built-in Python protocol powers the @property decorator under the hood?
A. Context Manager Protocol B. Iterator Protocol C. Descriptor Protocol D. Buffer Protocol Answer: C Explanation: property is a descriptor implementing __get__, __set__, and __delete__ methods to intercept attribute access.
2. What fatal error occurs if a setter method assigns to self.attribute_name = value instead of self._attribute_name = value?
A. AttributeError B. RecursionError (maximum recursion depth exceeded) C. SyntaxError D. MemoryError Answer: B Explanation: Assigning to the public property name inside its own setter re-invokes the setter continuously until Python's call stack is exhausted with a RecursionError.
3. How does functools.cached_property differ from standard @property?
A. cached_property can only return integers B. cached_property calculates the value once on first access and stores the result directly in the instance's __dict__ for subsequent fast lookups C. cached_property is removed in Python 3.12 D. cached_property saves values to disk Answer: B Explanation: cached_property evaluates the method only on first access and caches the result on the instance, bypassing repeated calculation.
4. How can you make a property strictly read-only?
A. Prepend the method name with @readonly B. Define the @property getter without providing a corresponding @<property>.setter C. Freeze the operating system D. Wrap the class in a tuple Answer: B Explanation: Omitting the @<prop>.setter method prevents attribute mutation; attempting to set the attribute raises an AttributeError: can't set attribute.
5. What decorator method is used to define custom cleanup logic when del obj.attribute is executed?
A. @property.delete B. @<attribute>.deleter C. @cleanup D. @destructor Answer: B Explanation: The @<attribute>.deleter decorator registers the function invoked when the del statement targets that property.
Method Resolution Order (MRO)
Continue learning with hands-on practice, examples, and exercises in the upcoming topic.
Related Lessons
| Previous Lesson | Next Lesson |
|---|---|
| Class and Static Methods Advanced | Method Resolution Order (MRO) |
Practice Quiz
Test your understanding of this lesson with 5 questions. Each question has one correct answer.