The @property decorator in Python transforms a class method into a attribute-like interface. This allows methods to be accessed without invoking parentheses, while also enabling the creation of read-only or computed class attributes.
Accessing Methods as Attributes
Applying the @property decorator to a method permits its retrieval using attribute syntax. Contrast this with a standard method, which requires parentheses for execution.
class TemperatureSensor:
@property
def current_reading(self):
return 23.5
def retrieve_reading(self):
return 23.5
sensor = TemperatureSensor()
print(sensor.current_reading) # Output: 23.5
print(sensor.retrieve_reading()) # Output: 23.5
Attempting to invoke a property-decorated method with parentheses results in a TypeError. Because current_reading now operates as an attribute, the evaluated float value is not a callable object.
# Raises: TypeError: 'float' object is not callable
print(sensor.current_reading())
Conversely, omitting parentheses on a standard method does not execute it. Instead, it returns a reference to the bound method object itself.
# Output: <bound method TemperatureSensor.retrieve_reading of ...>
print(sensor.retrieve_reading)
Enforcing Read-Only Attributes
Python does not enforce strict private access modifiers. By leveraging @property, internal variables can be shielded from external modification. Defining only a getter exposes the value safely while preventing assignment.
class UserProfile:
def __init__(self):
self._internal_id = 42
@property
def identifier(self):
return self._internal_id
profile = UserProfile()
print(profile.identifier) # Output: 42
Users interact with identifier without needing to know the underlying _internal_id variable. Any attempt to overwrite the property directly will raise an AttributeError, securing the internal state from unintended updates.
# Raises: AttributeError: can't set attribute
profile.identifier = 99