@property используется для создания вычисляемых атрибутов класса. Вместо хранения значения, атрибут вычисляется "на лету" при обращении к нему. Можно комбинировать с другими декораторами, например, @lru_cache для мемоизации результатов вычислений.
from functools import lru_cache
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value < 0:
raise ValueError("Radius cannot be negative")
self._radius = value
@property
@lru_cache(maxsize=None)
def area(self):
print("Calculating area...")
return 3.14159 * self._radius ** 2
В этом примере, area - вычисляемый атрибут, который мемоизирован. Setter для radius используется для контроля изменения радиуса.
Использование @property с декораторами позволяет создавать вычисляемые атрибуты, которые выглядят и используются как обычные атрибуты, но их значения генерируются "на лету" при обращении к ним. Это мощный механизм для инкапсуляции логики вычислений и поддержания консистентности данных.
Основная идея состоит в том, что @property определяет метод, который будет вызываться при попытке получить значение атрибута. Дополнительно, можно использовать @ и @ для определения методов, которые будут вызываться при попытке установить или удалить значение атрибута соответственно. В случае вычисляемых атрибутов, setter и deleter обычно не используются, потому что атрибут вычисляется и не должен устанавливаться напрямую.
Пример использования @property с декораторами для вычисляемого атрибута:
class Circle:
def __init__(self, radius):
self._radius = radius # Используем _radius, чтобы избежать конфликта имен
@property
def radius(self):
"""Возвращает радиус круга."""
return self._radius
@radius.setter
def radius(self, value):
"""Устанавливает радиус круга. Проверяет, что радиус положительный."""
if value <= 0:
raise ValueError("Радиус должен быть положительным")
self._radius = value
@property
def area(self):
"""Вычисляет и возвращает площадь круга."""
return 3.14159 * self._radius * self._radius
@property
def diameter(self):
"""Вычисляет и возвращает диаметр круга."""
return 2 * self._radius
В этом примере:
radius - обычный атрибут с getter и setter.area - вычисляемый атрибут, который возвращает площадь круга, основанную на текущем радиусе.diameter - вычисляемый атрибут, возвращающий диаметр.Ключевые моменты:
@property преобразует метод area в атрибут, к которому можно обращаться как к circle.area, без необходимости вызова метода как circle.area().area вычисляется только при обращении к нему. Если радиус изменится, новое значение площади будет вычислено при следующем обращении к circle.area.@radius.setter позволяет контролировать процесс присвоения нового значения радиусу, добавляя валидацию. Это важно для поддержания целостности данных.setter не определяют, если не требуется какой-то хитрый механизм обновления связанных данных.
Преимущества использования @property для вычисляемых атрибутов:
В заключение, @property с декораторами – это мощный и элегантный способ реализации вычисляемых атрибутов в Python, позволяющий создавать более чистый, поддерживаемый и расширяемый код.