Skip to content

[Python] Using @property Decorator To Convert Class Method Into Read-Only Attribute

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 and deleter 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


Read More

Tags:

Leave a Reply