Свойство Readonly (только для чтения) в Python

В этом руководстве вы узнаете, как определить свойство Readonly в Python и использовать его для определения вычисляемых свойств.

Что такое свойство Readonly в Python?

Чтобы определить свойство Readonly в Python, вам необходимо создать свойство только с геттером. Однако на самом деле оно доступен не только для чтения, поскольку вы всегда можете получить доступ к базовому атрибуту и изменить его. Свойства read-only полезны в некоторых случаях, например, для вычисляемых свойств.

В следующем примере определяется класс Circle с атрибутом radius и методом area():

import math


class Circle:
    def __init__(self, radius):
        self.radius = radius

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

Следующий код создает новый объект Circle и возвращает его площадь:

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

Выход:

314.1592653589793

Этот код работает отлично.

Но было бы более естественно, чтобы площадь была свойством объекта Circle, а не методом. Чтобы сделать метод area() свойством класса Circle, вы можете использовать декоратор @property следующим образом:

import math


class Circle:
    def __init__(self, radius):
        self.radius = radius

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


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

Площадь рассчитывается на основе атрибута radius. Поэтому его часто называют вычисляемым свойством.

Кэширование вычисляемых свойств

Предположим, вы создаете новый объект Circle и много раз обращаетесь к свойству area. Каждый раз площадь приходится пересчитывать, что неэффективно.

Чтобы сделать процесс более производительным, вам нужно пересчитывать площадь круга только при изменении радиуса. Если радиус не изменится, вы можете повторно использовать ранее рассчитанную площадь.

Для этого вы можете использовать технику кэширования:

  • Сначала вычислите площадь и сохраните ее в кэше.
  • Во-вторых, если радиус изменится, сбросьте область. В противном случае верните площадь прямо из кэша без пересчета.

Следующее определяет новый класс Circle со свойством кэшированной области:

import math


class 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

Как это работает:

  • Сначала установите для _area значение None в методе __init__. Атрибут _area — это кэш, в котором хранится вычисленная площадь.
  • Во-вторых, если радиус изменится(в установщике), сбросьте значение _area на None.
  • В-третьих, определите вычисляемое свойство области. Свойство area возвращает _area, если оно не имеет значения None. В противном случае вычислите площадь, сохраните ее в _area и верните.
Похожие посты
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *