@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, позволяющий создавать более чистый, поддерживаемый и расширяемый код.