Summary: in this tutorial, you’ll learn how to define Python readonly property and how to use it to define computed properties.

## Introduction to the Python readonly property

To define a readonly property, you need to create a property with only the getter. However, it is not truly read-only because you can always access the underlying attribute and change it.

The read-only properties are useful in some cases such as for computed properties.

The following example defines a class called `Circle` that has a `radius` attribute and an `area()` method:

`import mathclass Circle: def __init__(self, radius): self.radius = radius`

` def area(self): return math.pi * self.radius ** 2`

Code language: Python (python)

And the following creates a new `Circle` object and returns its area:

`c = Circle(10) print(c.area())`

Code language: Python (python)

Output:

`314.1592653589793`

Code language: Python (python)

This code works perfectly fine.

But it would be more natural that the area is a property of the `Circle` object, not a method. To make the `area()` method as a property of the `Circle` class, you can use the `@property` decorator as follows:

`import mathclass Circle: def __init__(self, radius): self.radius = radius @property def area(self): return math.pi * self.radius ** 2`

`c = Circle(10) print(c.area)`

Code language: Python (python)

The area is calculated from the `radius` attribute. Therefore, it’s often called a calculated or computed property.

## Cache calculated properties

Suppose you create a new circle object and access the area property many times. Each time, the area needs to be recalculated, which is not efficient.

To make it more performant, you need to recalculate the area of the circle only when the radius changes. If the radius doesn’t change, you can reuse the previously calculated area.

To do it, you can use the caching technique:

• First, calculate the area and save it in a cache.
• Second, if the radius changes, reset the area. Otherwise, return the area directly from the cache without recalcuation.

The following defines the new `Circle` class with cached `area` property:

`import mathclass Circle: def __init__(self, radius): self._radius = radius self._area = None @property def radius(self): return self._radius @radius.setter def radius(self, value): if value < 0: raise ValueError('Radius must be positive') if value != self._radius: self._radius = value self._area = None @property def area(self): if self._area is None: self._area = math.pi * self.radius ** 2`

` return self._area`

Code language: Python (python)

How it works.

First, set the `_area` to `None` in the `__init__` method. The _area attribute is the cache that stores the calculated area.

Second, if the radius changes (in the setter), reset the `_area` to `None`.

Third, define the `area` computed property. The `area` property returns `_area` if it is not `None`. Otherwise, calculate the area, save it into the `_area`, and return it.

## Summary

• Define only the getter to make a property readonly
• Do use computed property to make the property of a class more natural
• Use caching computed properties to improve the performance.