slots в Python: проверка полей и всей иерархии наследования
Напишите решение на Python и проверьте его на странице.
Другие упражнения по этой теме: Память Python: задачи на tracemalloc, утечки и slots.
Аудит схемы слотов
Модуль графовой аналитики обрабатывает миллионы узлов и регистрирует новые типы элементов через фабричный реестр. Чтобы миллионы объектов не расходовали лишнюю память на персональные словари атрибутов __dict__, каждый регистрируемый класс обязан на всех уровнях своей иерархии наследования использовать дескрипторы __slots__ и строго следовать переданному списку ожидаемых полей.
Перед добавлением типа в систему инспектор реестра изучает класс-кандидат и всех его предков. Если в собственном словаре __dict__ самого класса или любого из его предков обнаруживается дескриптор __dict__, это означает пропуск __slots__, и инспектор отклоняет регистрацию с ошибкой словаря.
Если словарей нет, инспектор переходит к проверке состава полей по всей цепочке наследования. Появление слота с одним и тем же именем одновременно у класса и любого его предка считается ошибкой дублирования. Наконец, итоговое объединение всех собственных и унаследованных слотов должно строго совпадать с эталонным множеством: любая нехватка или появление лишнего поля приводит к ошибке несоответствия схемы.
Определите, проходит ли предложенный класс проверку инспектора или его регистрация завершается одной из положенных ошибок.
Что уже дано
В редакторе объявлена заготовка функции audit_slot_schema(cls, expected_fields). Вспомогательные средства для сборки проверочных классов уже доступны во время исполнения и не требуют повторной реализации.
Что нужно сделать
Реализуйте функцию audit_slot_schema(cls, expected_fields).
Параметры функции:
cls— исследуемый класс Python. Необходимо проверить сам класс и каждого его уникального предка, включаяobject.expected_fields— кортеж строк с уникальными именами ожидаемых публичных полей (от 0 до 64 элементов).
Функция выполняет инспекцию схемы хранения и возвращает строковый статус. Проверки выполняются в строгом порядке приоритета, и при первом нарушении возвращается соответствующий код:
"DICT_ERROR"— в собственном пространстве имён классаclsили любого из его уникальных предков обнаружен дескриптор экземпляра__dict__(включая явное объявление"__dict__"в__slots__)."DUPLICATE_SLOT"— одно и то же имя слота объявлено на разных уровнях иерархии наследования (у класса и предка или у нескольких предков)."SCHEMA_MISMATCH"— объединение всех объявленных слотов класса и его предков отличается от множестваexpected_fields(не хватает полей или присутствуют лишние)."OK"— класс и вся его иерархия успешно прошли все три проверки.
Правила проверки и соглашения об окружении:
- Инспектируйте непосредственно классы и их дескрипторы, а не флаги экземпляров. Инстанцировать классы (вызывать
cls(...)) не требуется и запрещено: конструкторы могут требовать аргументы или вызывать исключения. - Не изменяйте исследуемые классы: запрещено модифицировать их дескрипторы хранения, список базовых классов или порядок разрешения методов (MRO).
- При ромбовидном наследовании общий предок должен быть проверен ровно один раз, а не для каждой ветки наследования отдельно.
- Если дочерний класс объявляет
__slots__ = (), он сохраняет слоты предков и не создаёт словарь. Если же класс-наследник вовсе опускает объявление__slots__, для него создаётся дескриптор__dict__. - Присвоение
__slots__классу после его создания не удаляет уже существующий дескриптор словаря. - Имена слотов в объявлениях состоят из 1–32 ASCII-символов (публичные идентификаторы Python без манглинга имен и без слота
__weakref__). Внутри одного объявления слотов дубликаты отсутствуют. - Общее число уникальных классов в иерархии составляет от 1 до 24, глубина наследования без учёта
object— от 1 до 8, а число прямых базовых классов — от 1 до 3. Каждое объявление содержит от 0 до 8 слотов.
Ввод и вывод
Стандартные потоки ввода stdin и вывода stdout в решении не используются: считывать ввод и вызывать print() не нужно. После выполнения кода учащегося проверяющая система считывает из пространства имён модуля функцию верхнего уровня audit_slot_schema и вызывает её с проверочными аргументами.
Пример использования
class Node:
__slots__ = ('identifier',)
class Edge(Node):
__slots__ = ('weight',)
print(audit_slot_schema(Edge, ('identifier', 'weight')))
class Broken(Edge):
pass
print(audit_slot_schema(Broken, ('identifier', 'weight')))
Вывод:
OK DICT_ERROR
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Связанные задачи
- slots в Python: за счёт чего экономится память
- Наследование и slots в Python: почему возвращается dict
- Tracemalloc Python: группировка выделений памяти по стеку вызовов
- Утечка памяти Python: найдите буфер, удерживающий объекты
- Удаление ключа из ChainMap в Python: проверка поведения del
- Обратный индекс на Python: группировка уникальных значений через defaultdict
