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 элементов).

Функция выполняет инспекцию схемы хранения и возвращает строковый статус. Проверки выполняются в строгом порядке приоритета, и при первом нарушении возвращается соответствующий код:

  1. "DICT_ERROR" — в собственном пространстве имён класса cls или любого из его уникальных предков обнаружен дескриптор экземпляра __dict__ (включая явное объявление "__dict__" в __slots__).
  2. "DUPLICATE_SLOT" — одно и то же имя слота объявлено на разных уровнях иерархии наследования (у класса и предка или у нескольких предков).
  3. "SCHEMA_MISMATCH" — объединение всех объявленных слотов класса и его предков отличается от множества expected_fields (не хватает полей или присутствуют лишние).
  4. "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
РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Связанные задачи