Использование свойств (property): геттеры, сеттеры и делитеры
Зачем нужны свойства в Python? 🛡️
Представь: ты создал класс Person с атрибутом age. Всё работает, пока кто-то не присвоит отрицательное значение — и вот уже человек "моложе" Большого взрыва! 💥 Тут на помощь приходят свойства (property) — элегантный способ контролировать доступ к атрибутам.
class Person:
def __init__(self, age):
self.age = age # Опасно! Можно задать age = -100
Геттеры и сеттеры без property
Обычный подход — методы get_age() и set_age(), но это не "питонично" 🐍:
class Person:
def __init__(self, age):
self._age = age # Защищённый атрибут
def get_age(self):
return self._age
def set_age(self, value):
if value < 0:
raise ValueError("Возраст не может быть отрицательным")
self._age = value
person = Person(25)
person.set_age(30) # Неудобный синтаксис
Волшебство @property ✨
Декоратор @property превращает метод в атрибут, сохраняя контроль:
class Person:
def __init__(self, age):
self._age = age
@property
def age(self):
"""Геттер: возвращает возраст"""
return self._age
@age.setter
def age(self, value):
"""Сеттер: проверяет возраст"""
if value < 0:
raise ValueError("🚨 Возраст не может быть отрицательным!")
self._age = value
danila = Person(30)
danila.age = 31 # Вызывается сеттер
print(danila.age) # Вызывается геттер
Как это работает:
@propertyсоздаёт геттер@age.setterопределяет сеттер- Обращение к
ageвыглядит как к атрибуту, но вызывает методы!
Делитеры для cleanup 🧹
Хотите удалить атрибут с проверками? Используйте @property.deleter:
@age.deleter
def age(self):
print("⚠️ Возраст удалён!")
del self._age
del danila.age # Вызовет делитер
Реальный пример: валидация email 📧
class User:
def __init__(self, email):
self.email = email # Используем сеттер
@property
def email(self):
return self._email
@email.setter
def email(self, value):
if "@" not in value:
raise ValueError("Это не email! ❌")
self._email = value
user = User("danila@example.com")
user.email = "invalid" # Вызовет ValueError
Когда использовать property?
✅ Валидация данных
✅ Ленивые вычисления (кэширование)
✅ Совместимость с legacy-кодом
✅ Замена простых методов для удобства
Продвинутый трюк: property в действии 🎩
Создадим "вычисляемое" свойство:
class Circle:
def __init__(self, radius):
self.radius = radius
@property
def area(self):
return 3.14 * self.radius ** 2
circle = Circle(5)
print(f"Площадь круга: {circle.area}") # 78.5
Важные нюансы ⚠️
- Не злоупотребляйте — для простых атрибутов property избыточны
- Иммутабельные свойства — опустите сеттер, чтобы запретить изменение
- Производительность — вызов property медленнее прямого доступа к атрибуту
Хочешь глубже разобрать ООП? Рекомендую курс Данилы Бежина на YouTube: youtube.com/@DanilaBezhin. Там есть разбор property и других крутых фишек Python! 🔥