Last Updated on 2024-08-27 by Clay
In Python class construction, the @property
decorator is commonly used and has significant benefits. Its main purpose is to transform a class method into a read-only attribute, allowing users to retrieve computed results via attribute access.
Another advantage is that it makes the code more intuitive to read and maintain by hiding some of the computation details.
Usage
Let’s look at a class that converts a timestamp into date strings, where each class method returns the date in a different format. Once we modify the timestamp, calling the corresponding @property methods will give us the formatted results (and the usage is just like accessing class attributes).
import datetime
class TimestampFormatter:
def __init__(self, timestamp):
self._timestamp = timestamp
@property
def date_slash(self):
""" Return format yyyy/mm/dd """
date = datetime.datetime.fromtimestamp(self._timestamp)
return date.strftime('%Y/%m/%d')
@property
def date_dash(self):
""" Return format yyyy-mm-dd """
date = datetime.datetime.fromtimestamp(self._timestamp)
return date.strftime('%Y-%m-%d')
@property
def date_dot(self):
""" Return format yyyy.mm.dd """
date = datetime.datetime.fromtimestamp(self._timestamp)
return date.strftime('%Y.%m.%d')
@property
def date_space(self):
""" Return format yyyy mm dd """
date = datetime.datetime.fromtimestamp(self._timestamp)
return date.strftime('%Y %m %d')
if __name__ == "__main__":
current_timestamp = datetime.datetime.now().timestamp()
# Create TimestampFormatter instance
formatter = TimestampFormatter(int(current_timestamp))
# Print different format
print("Date with slashes:", formatter.date_slash)
print("Date with dashes:", formatter.date_dash)
print("Date with dots:", formatter.date_dot)
print("Date with spaces:", formatter.date_space)
Output:
Date with slashes: 2024/08/27
Date with dashes: 2024-08-27
Date with dots: 2024.08.27
Date with spaces: 2024 08 27
Intuitively, this feels like we are setting a class instance's attribute, and other related attributes update accordingly. This is particularly intuitive when different attributes are interdependent within a class.
Extended Usage
Setter Method
setter
methods are a feature of the @property
decorator used to set or modify the value of an attribute. When additional checks or conversions are needed when assigning values, such as data validation or auto-formatting, a setter
is ideal.
Basic Usage
We can define a setter by placing @<property_name>.setter
before the method (I initially didn’t understand where <property_name>
came from, but I later realized it’s the method we define). Here’s an example:
class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, value):
if not isinstance(value, str):
raise TypeError("Name must be a string")
self._name = value
In this example, when we attempt to set the name
attribute, the setter
method first checks if the new value is a string. If not, it raises a TypeError
.
Deleter Method
deleter
methods define what happens when an attribute is deleted, such as cleaning up or releasing resources. This is particularly useful when dealing with files or database connections.
Basic Usage
You can define a deleter
by adding @<property_name>.deleter
before the method. Here’s an example:
class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.deleter
def name(self):
print("Deleting name...")
del self._name
When the del
operation is applied to the name
attribute, the deleter
method is invoked to handle logging or other cleanup tasks.
In summary, using @property
offers the following benefits:
- Exception Handling: Add exception handling in
setter
anddeleter
methods to prevent incorrect usage from damaging the object - Dependent Attributes: If one attribute’s value depends on another,
@property
ensures all related attributes are updated in sync - Caching Computed Values: For attributes with expensive computations, the result can be cached after the first calculation, and subsequent accesses return the cached value unless the underlying data changes
References
- Built-in Functions — Python 3.12.5 documentation
- Stack Overflow - How to document fields and properties in Python?