Декораторы @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— управляет удалением.- Где использовать? Валидация, вычисляемые значения, защита данных.
Теперь ваши классы стали надёжнее! 🛡️✨