The `@property` [decorator](/tutorials/decorators) in Python provides a way to manage attributes in object-oriented programming. It allows you to define methods in a class that behave like attributes, providing getter, setter, and deleter functionality. This can lead to more concise and maintainable code by encapsulating accessor and mutator methods in a Pythonic way. ### Basic Usage of the `@property` Decorator Let's start with a simple example to see how the `@property` decorator works. #### Defining a Getter Here is how you define a getter method using the `@property` decorator:
class Circle: def __init__(self, radius): self._radius = radius @property def radius(self): return self._radius # Example usage: c = Circle(5) print(c.radius) # Output: 5
5
In this example: - The `radius` method is decorated with `@property`, making it accessible like an attribute. - We use an underscore `_radius` to indicate that it should be treated as a private attribute. ### Defining a Setter You can define a setter method to update the property while maintaining control over how it is set.
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 cannot be negative") self._radius = value # Example usage: c = Circle(5) print(c.radius) # Output: 5 c.radius = 10 print(c.radius) # Output: 10 # c.radius = -1 # Uncommenting this line will raise a ValueError
5 10
In this example: - The `@property` decorator defines the getter. - The `@radius.setter` decorator defines the setter, which includes validation logic to ensure the radius is non-negative. ### Defining a Deleter You can also define a deleter method to delete the property.
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 cannot be negative") self._radius = value @radius.deleter def radius(self): del self._radius # Example usage: c = Circle(5) print(c.radius) # Output: 5 del c.radius # print(c.radius) # Uncommenting this line will raise an AttributeError
5
In this snippet: - The `@radius.deleter` decorator defines the deleter method. ### Calculated Properties The `@property` decorator is useful for calculated properties that are based on other attributes.
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 cannot be negative") self._radius = value @property def area(self): import math return math.pi * self._radius ** 2 # Example usage: c = Circle(5) print(c.radius) # Output: 5 print(c.area) # Output: 78.53981633974483 (π * 5^2)
5 78.53981633974483
The `area` property is calculated based on the `radius` attribute. ### Providing Read-Only Attributes With the `@property` decorator, you can create read-only attributes by defining only the getter method.
class Person: def __init__(self, first_name, last_name): self._first_name = first_name self._last_name = last_name @property def full_name(self): return f"{self._first_name} {self._last_name}" # Example usage: p = Person("John", "Doe") print(p.full_name) # Output: John Doe # p.full_name = "Jane Doe" # Uncommenting this line will raise an AttributeError
John Doe
In this example, the `full_name` property is read-only because only a getter method is provided. ### Using `@property` with Dataclasses If you are using Python's `dataclasses` module, you can combine it with `@property` to manage attributes.
from dataclasses import dataclass @dataclass class Rectangle: length: float width: float @property def area(self): return self.length * self.width # Example usage: r = Rectangle(5, 3) print(r.area) # Output: 15
15
Here, the `Rectangle` class is a dataclass, and the `area` is a calculated property. ### Conclusion The `@property` decorator in Python provides a powerful and Pythonic way to manage attributes in classes. It allows you to encapsulate getter, setter, and deleter methods to create managed attributes. This leads to cleaner and more maintainable code, especially when dealing with complex logic for attribute access and modification.