← Назад к вопросам

Зачем нужен дескриптор?

3.0 Senior🔥 121 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое дескриптор?

Дескриптор — это объект, который определяет, как атрибут класса ведёт себя при доступе, присваивании или удалении. Он реализует один или несколько методов из протокола дескриптора: __get__, __set__ и __delete__.

Основные методы дескриптора

class Descriptor:
    def __get__(self, obj, objtype=None):
        # Вызывается при доступе к атрибуту
        return "значение"
    
    def __set__(self, obj, value):
        # Вызывается при присваивании значения
        pass
    
    def __delete__(self, obj):
        # Вызывается при удалении атрибута
        pass

Типы дескрипторов

Data descriptor (дескриптор данных) — имеет методы __set__ и/или __delete__. Приоритет: сам дескриптор > словарь экземпляра.

Non-data descriptor (дескриптор без записи) — имеет только __get__. Приоритет: словарь экземпляра > дескриптор.

Практические примеры

1. Валидация значения (property)

class Age:
    def __get__(self, obj, objtype=None):
        return obj._age
    
    def __set__(self, obj, value):
        if not isinstance(value, int) or value < 0:
            raise ValueError("Возраст должен быть положительным числом")
        obj._age = value

class Person:
    age = Age()
    
    def __init__(self, age):
        self.age = age

p = Person(25)  # OK
p.age = -5  # ValueError

2. Ленивая инициализация

class LazyProperty:
    def __init__(self, func):
        self.func = func
        self.name = func.__name__
    
    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        value = self.func(obj)
        setattr(obj, self.name, value)  # Кэшируем в __dict__
        return value

class DataProcessor:
    @LazyProperty
    def processed_data(self):
        print("Вычисляю данные...")
        return expensive_operation()

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

class Logged:
    def __init__(self, name):
        self.name = name
    
    def __get__(self, obj, objtype=None):
        print(f"Доступ к {self.name}")
        return obj.__dict__.get(self.name)
    
    def __set__(self, obj, value):
        print(f"Присвоение {self.name} = {value}")
        obj.__dict__[self.name] = value

Зачем нужны дескрипторы?

  • Контроль доступа — валидация, ограничение прав
  • Мощная абстракция — реализованы через дескрипторы: property, classmethod, staticmethod
  • Производительность — оптимизация горячих путей
  • Паттерны — Observable, Proxy, Strategy
  • ORM и фреймворки — Django ORM, SQLAlchemy используют дескрипторы для связей

Важные моменты

  • Дескрипторы работают только при доступе через класс/экземпляр, не через __dict__
  • Data descriptors имеют приоритет над атрибутами экземпляра
  • @property — это встроенный дескриптор
  • Методы класса и статические методы — тоже дескрипторы