Что такое декораторы свойств (@property)?python-27

Декоратор @property — это встроенный декоратор Python, который позволяет превращать методы класса в "свойства" (properties), то есть атрибуты, доступ к которым контролируется через методы.

Основная концепция

@property предоставляет элегантный способ:

  1. Контролировать доступ к атрибутам
  2. Добавлять логику при чтении/записи атрибутов
  3. Создавать вычисляемые атрибуты
  4. Обеспечивать обратную совместимость при изменении внутренней реализации

Базовый пример

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 must be positive")
        self._radius = value

    @property
    def area(self):
        """Вычисляемое свойство (нет сеттера)"""
        return 3.14 * self._radius ** 2

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

  1. Геттер (чтение): Декорированный @property метод вызывается при обращении к атрибуту
  2. Сеттер (запись): Метод с декоратором @<property>.setter вызывается при присвоении
  3. Делитер (удаление): Метод с декоратором @<property>.deleter вызывается при del

Продвинутое использование

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

class DataProcessor:
    def __init__(self, data):
        self._data = data
        self._result_cache = None

    @property
    def processed_data(self):
        if self._result_cache is None:
            print("Выполняю сложные вычисления...")
            self._result_cache = self._heavy_processing()
        return self._result_cache

    def _heavy_processing(self):
        return [x * 2 for x in self._data]

2. Запрет изменения свойства

class Constants:
    @property
    def PI(self):
        return 3.141592653589793

    # Не определяем сеттер, поэтому PI нельзя изменить

3. Логирование доступа к свойствам

class LoggedAttribute:
    def __init__(self, value):
        self.value = value

    @property
    def value(self):
        print("Доступ на чтение")
        return self._value

    @value.setter
    def value(self, new_value):
        print(f"Изменение значения с {self._value} на {new_value}")
        self._value = new_value

Отличия от обычных методов

Характеристика Обычный метод @property
Синтаксис доступа obj.method() obj.property
Может принимать args Да Нет
Может изменять state Да Только через сеттер
Вычисление на лету При каждом вызове При каждом обращении

Поддержка в IDE

Свойства правильно определяются в:

  1. Автодополнении кода
  2. Подсказках типов
  3. Документации (help() и docstrings)

Резюмируем

  1. @property превращает методы в атрибуты с контролируемым доступом
  2. Позволяет добавлять валидацию и логику при работе с атрибутами
  3. Создает более "питонячий" интерфейс для классов
  4. Может использоваться для вычисляемых и кешируемых значений
  5. Обеспечивает инкапсуляцию с сохранением простого синтаксиса доступа

Используйте свойства, когда нужно:

  • Контролировать доступ к атрибутам
  • Изменить внутреннюю реализацию без изменения API
  • Добавить логику при чтении/записи атрибутов
  • Создать вычисляемые атрибуты
Смотрите так же