Декораторы @property, @setter, @deleter: управление доступом к атрибутам

❓ Зачем нужны декораторы @property, @setter, @deleter?

В Python всё — объекты. Их атрибуты можно свободно читать и изменять... но иногда это приводит к хаосу! 🌀

Пример проблемы:

class User:
    def __init__(self, name):
        self.name = name  # А если передать число? Или пустую строку?

user = User(123)  # Ой, имя — это число? Нелогично!

Декораторы @property, @setter, @deleter помогают:
- Контролировать доступ к атрибутам.
- Валидировать данные перед записью.
- Вычислять значения «на лету».
- Скрывать внутреннюю реализацию.


🛠️ Как создавать «умные» атрибуты

1️⃣ Базовый @property — геттер

Превращаем метод в атрибут, доступный только для чтения.

class Circle:
    def __init__(self, radius):
        self._radius = radius  # _ — договорённость, что это «внутренний» атрибут

    @property
    def radius(self):
        """Геттер: возвращает радиус с докстрингом."""
        print("Доступ к радиусу!")
        return self._radius

circle = Circle(10)
print(circle.radius)  # Выведет: "Доступ к радиусу!" и 10

🔹 Что произошло?
- radius теперь не метод, а свойство (property).
- Обращение circle.radius автоматически вызывает метод под капотом.


2️⃣ @имя_свойства.setter — сеттер

Контролируем запись значения.

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("Радиус должен быть положительным!")
        self._radius = value

circle = Circle(5)
circle.radius = 12  # ОК
circle.radius = -3  # ValueError!

🔹 Фишки:
- Проверка данных при присвоении.
- Исключения с понятными сообщениями.


3️⃣ @имя_свойства.deleter — делитер

Управляем удалением атрибута.

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

    @property
    def radius(self):
        return self._radius

    @radius.deleter
    def radius(self):
        print("Радиус удалён! Но это можно логировать или запретить.")
        del self._radius

circle = Circle(8)
del circle.radius  # Выведет сообщение и удалит _radius

🔥 Реальные кейсы применения

📏 Валидация данных

class Temperature:
    def __init__(self, celsius):
        self.celsius = celsius  # Используем сеттер!

    @property
    def celsius(self):
        return self._celsius

    @celsius.setter
    def celsius(self, value):
        if not -273.15 <= value <= 1000:
            raise ValueError("Нереальная температура!")
        self._celsius = value

    @property
    def fahrenheit(self):
        """Вычисляемое свойство: градусы Фаренгейта."""
        return self._celsius * 9/5 + 32

🔒 Запрет изменения

class DatabaseConfig:
    def __init__(self, host):
        self._host = host

    @property
    def host(self):
        return self._host

    # Нет сеттера — значение нельзя изменить после создания!
config = DatabaseConfig("localhost")
config.host = "hacker.com"  # AttributeError: can't set attribute

💡 Советы от Данилы Бежина

  • Не злоупотребляйте свойствами. Если логика простая — используйте обычные атрибуты.
  • Именуйте «внутренние» атрибуты с _ (например, _value), чтобы показать, что они приватные.
  • Дополнительные материалы — разбор декораторов в плейлисте по ООП.

🏆 Итоги

  • @property — делает метод атрибутом (геттер).
  • @setter — контролирует изменение атрибута.
  • @deleter — управляет удалением.
  • Где использовать? Валидация, вычисляемые значения, защита данных.

Теперь ваши классы стали надёжнее! 🛡️✨

Скрыть рекламу навсегда

🎥 YouTube: программирование простым языком

Канал, где я спокойно и по шагам объясняю сложные темы — без заумных терминов и лишней теории.

Подходит, если раньше «не заходило», но хочется наконец понять.

▶️ Смотреть курсы на YouTube