Что такое descriptors и как они связаны с геттерами и сеттерами
Что проверяют
Для аналитика это вопрос на чтение чужого кода, а не на написание библиотек. За ним стоит проверка: понимаете ли вы, откуда в моделях берутся валидация и вычисляемые поля и почему одно и то же имя у класса и у экземпляра ведёт себя по-разному.
Как отвечать
Дескриптор это объект, который лежит атрибутом класса и перехватывает обращение к этому атрибуту у экземпляров. Перехват описывают методы __get__, __set__ и __delete__. Геттер и сеттер тут не отдельный паттерн, а частный случай: встроенный property сам является дескриптором.
Дальше стоит показать, что механизм вам знаком по инструментам. На дескрипторах построены колонки SQLAlchemy и поля моделей Django: они объявлены атрибутами класса, и поэтому выражение вида Заказ.сумма > 1000 на уровне класса собирает условие для запроса, а заказ.сумма у экземпляра возвращает число. Там же живут правила валидации: ограничение описано один раз рядом с полем, а не размазано по вызывающему коду, ровно как ограничение на колонку в базе.
class Positive:
def __set_name__(self, owner, name):
self.slot = "_" + name
def __get__(self, obj, owner=None):
return self if obj is None else getattr(obj, self.slot)
def __set__(self, obj, value):
if value < 0:
raise ValueError("нужно неотрицательное значение")
setattr(obj, self.slot, value)Где спотыкаются
Создают дескриптор внутри __init__, то есть кладут его на экземпляр. Механизм смотрит только на класс, поэтому ничего не срабатывает и в атрибуте лежит обычный объект. Работает лишь объявление на уровне класса.
Хранят значение в самом дескрипторе, в его self. Дескриптор один на класс, и все экземпляры начинают делить одно значение: поменяли сумму в одной строке, она изменилась во всех. Значение хранят в словаре экземпляра, имя для него даёт __set_name__.
Называют дескрипторы универсальной заменой геттеров и сеттеров. Если правило нужно одному полю одного класса, property короче и читается лучше. Дескриптор окупается, когда одно и то же правило повторяется у многих полей или классов, и это же соображение отличает уместный слой абстракции от лишнего.