Property Decorators in Python
Property decorators in Python provide a way to define managed attributes in a class. The @property
decorator allows us to define methods that act like attributes while implementing getter, setter, and deleter functionality. This helps in data encapsulation and validation.
Syntax
class ClassName:
@property
def attribute_name(self):
return self._attribute_name
@attribute_name.setter
def attribute_name(self, value):
self._attribute_name = value
@attribute_name.deleter
def attribute_name(self):
del self._attribute_name
How Property Decorators Work
The @property
decorator converts a method into a getter. This allows us to access it like an attribute without using parentheses. The @attribute_name.setter
decorator allows modifying the attribute, and @attribute_name.deleter
allows deleting it.
Examples
1. Using @property
to Define a Read-Only Attribute
In this example, we define a class Circle
with a read-only attribute area
. The value is calculated dynamically whenever it is accessed.
import math
class Circle:
def __init__(self, radius):
self._radius = radius # Private variable to store radius
@property
def area(self):
"""Computes the area of the circle dynamically."""
return math.pi * self._radius ** 2
# Creating an instance of Circle
c = Circle(5)
# Accessing the area property
print("Circle area:", c.area)
# Trying to modify area (This will cause an AttributeError)
# c.area = 100 # Uncommenting this line will raise an error
Output:
Circle area: 78.53981633974483
Here, we used @property
to define area
as a read-only attribute. Trying to assign a new value to area
would result in an error because we have not defined a setter.
2. Using @property
with a Setter
Here, we define a Person
class where the age
attribute has both a getter and a setter. The setter ensures that the value assigned to age
is valid.
class Person:
def __init__(self, name, age):
self._name = name
self._age = age # Private variable to store age
@property
def age(self):
"""Gets the age value."""
return self._age
@age.setter
def age(self, value):
"""Sets the age value, ensuring it is a positive number."""
if value < 0:
raise ValueError("Age cannot be negative.")
self._age = value
# Creating an instance of Person
p = Person("Arjun", 25)
# Accessing age property
print("Person's age:", p.age)
# Updating age
p.age = 30
print("Updated age:", p.age)
# Trying to assign a negative age (This will raise a ValueError)
# p.age = -5 # Uncommenting this line will raise an error
Output:
Person's age: 25
Updated age: 30
Here, the @age.setter
ensures that the age cannot be negative. Trying to set a negative value results in an error.
3. Using @property
with a Deleter
We add a deleter to the Person
class, allowing us to delete the age attribute.
class Person:
def __init__(self, name, age):
self._name = name
self._age = age # Private variable to store age
@property
def age(self):
"""Gets the age value."""
return self._age
@age.setter
def age(self, value):
"""Ensures age is positive before assigning."""
if value < 0:
raise ValueError("Age cannot be negative.")
self._age = value
@age.deleter
def age(self):
"""Deletes the age attribute."""
print("Deleting age...")
del self._age
# Creating an instance of Person
p = Person("Arjun", 25)
# Deleting age attribute
del p.age
# Trying to access age after deletion (This will raise an AttributeError)
# print(p.age) # Uncommenting this line will raise an error
Output:
Deleting age...
When del p.age
is called, the deleter function runs and removes the _age
attribute. Trying to access p.age
after deletion results in an AttributeError
.
4. Using @property
to Compute a Derived Attribute
We can use @property
to compute a value dynamically. Here, we define a class Temperature
that converts between Celsius and Fahrenheit.
class Temperature:
def __init__(self, celsius):
self._celsius = celsius # Private variable to store Celsius value
@property
def fahrenheit(self):
"""Converts Celsius to Fahrenheit dynamically."""
return (self._celsius * 9/5) + 32
# Creating an instance of Temperature
temp = Temperature(25)
# Accessing the computed Fahrenheit value
print("Temperature in Fahrenheit:", temp.fahrenheit)
Output:
Temperature in Fahrenheit: 77.0
Since we did not define a setter, fahrenheit
is a read-only property derived from the _celsius
attribute.