Использование свойств (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)  # Вызывается геттер

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

  1. @property создаёт геттер
  2. @age.setter определяет сеттер
  3. Обращение к 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

Важные нюансы ⚠️

  1. Не злоупотребляйте — для простых атрибутов property избыточны
  2. Иммутабельные свойства — опустите сеттер, чтобы запретить изменение
  3. Производительность — вызов property медленнее прямого доступа к атрибуту

Хочешь глубже разобрать ООП? Рекомендую курс Данилы Бежина на YouTube: youtube.com/@DanilaBezhin. Там есть разбор property и других крутых фишек Python! 🔥

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

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

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

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

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