Python provides two primary approaches for implementing managed attributes: the @property decorator and the property() function. Both methods enable controlled access to instance attributes while maintaining clean syntax.
Using the @property Decorator
The @property decorator transforms methods into managed attributes, allowing you to define getter, setter, and deleter methods while using attribute-style access. This approach provides a clean way to implement validation and processing logic.
class TemperatureControl:
def __init__(self):
self._internal_temp = 20.0
@property
def temperature(self):
"""Current temperature in Celsius"""
return self._internal_temp
@temperature.setter
def temperature(self, new_temp):
if not isinstance(new_temp, (int, float)):
raise TypeError("Temperature must be numeric")
if new_temp < -273.15:
raise ValueError("Temperature below absolute zero")
self._internal_temp = new_temp
@temperature.deleter
def temperature(self):
self._internal_temp = None
thermostat = TemperatureControl()
print(thermostat.temperature)
thermostat.temperature = 25.5
print(thermostat.temperature)
del thermostat.temperature
print(thermostat.temperature)20.0
25.5
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 13, in temperature
AttributeError: 'TemperatureControl' object has no attribute '_internal_temp'Using the property() Function
The property() function offers an alternative way to create managed attributes by binding getter, setter, and deleter methods to a single attribute.
Syntax
property(fget=None, fset=None, fdel=None, doc=None)Parameters
- fget: Function to retrieve attribute value
- fset: Function to set attribute value
- fdel: Function to delete attribute
- doc: Documentation string for the property
class BankAccount:
def __init__(self, initial_balance=0):
self._balance = initial_balance
def get_balance(self):
return self._balance
def set_balance(self, amount):
if amount < 0:
raise ValueError("Balance cannot be negative")
self._balance = amount
def del_balance(self):
self._balance = 0
balance = property(
get_balance,
set_balance,
del_balance,
"Account balance in dollars"
)
account = BankAccount(1000)
print(account.balance)
account.balance = 1500
print(account.balance)
del account.balance
print(account.balance)1000
1500
0When an account instance accesses balance, Python automatically calls get_balance(). Setting account.balance triggers set_balance(), and del account.balance invokes del_balance(). This encapsulation allows you to maintain invariants and add validation logic while preserving attribute access syntax.