Python initsubclass: иерархический реестр классов
Напишите решение на Python и проверьте его на странице.
Другие упражнения по этой теме: Метаклассы и init_subclass Python: задачи на проверку классов.
Иерархический каталог документации
Модуль документации выстраивает справочные статьи в виде многоуровневого дерева классов. На вершине этой структуры находится корневой класс раздела, который задаёт общее пространство имён. Каждый дочерний подкласс может либо объявить конкретную статью, указав в заголовке строковый идентификатор topic_id, либо остаться промежуточным подразделом без этого параметра.
Хук __init_subclass__ базового класса перехватывает создание каждого нового подкласса и собирает его сквозной путь. Если идентификатор topic_id передан, хук формирует составной ключ вида f"{parent_path}/{topic_id}", где путь предка наследуется от ближайшего родительского раздела, и сохраняет класс в общем словаре каталога. Одинаковые короткие имена тем в разных родительских ветках регистрируются независимо, но любая попытка добавить дубликат полного составного пути должна сразу прерываться ошибкой ValueError.
Реализуйте базовый класс каталога, который автоматически строит полные пути статей при объявлении подклассов и защищает реестр от совпадения составных ключей.
Что уже дано
В редакторе объявлен базовый класс TopicCatalog с атрибутами path = 'docs' и catalog = {}, а также заготовкой метода __init_subclass__(cls, topic_id=None, **kwargs). Вспомогательная проверочная функция observe_topic_catalog доступна при выполнении тестов, её реализовывать не нужно.
Что нужно сделать
Реализуйте метод __init_subclass__(cls, topic_id=None, **kwargs) в классе TopicCatalog:
- Корневой класс определяет начальный путь
path = 'docs'и общий словарьcatalog(доступен какTopicCatalog.catalog). - Если при объявлении класса-наследника параметр
topic_idне передан (None), класс не регистрируется в каталоге. Его атрибутpathостаётся унаследованным от ближайшего родительского раздела, чтобы будущие потомки могли продолжить формирование пути от этой секции. - Если
topic_idпередан (строка от 0 до 40 ASCII-символов), сформируйте составной путьf"{parent_path}/{topic_id}", присвойте его атрибутуpathсоздаваемого класса и сохраните сам класс в общий словарьTopicCatalog.catalogпо этому ключу. - Если сформированный полный путь уже присутствует в каталоге, возбудите исключение семейства
ValueError, не заменяя ранее зарегистрированный класс. - Обеспечьте кооперативную маршрутизацию аргументов: извлеките
topic_id, а все остальные именованные аргументы (**kwargs) без изменений передайте вsuper().__init_subclass__(**kwargs). Если доobjectдойдут неизвестные параметры, стандартный механизм вызоветTypeError. - Ограничения: дерево поддерживает до 100 последовательных объявлений классов на ветку; конкатенация строк выполняется буквально через f-строку без нормализации слэшей.
Ввод и вывод
Стандартные потоки ввода stdin и вывода stdout в решении не используются: считывать ввод и вызывать print() не нужно. После выполнения кода учащегося проверяющая система считывает из пространства имён модуля класс верхнего уровня TopicCatalog и проверяет регистрацию наследуемых подклассов.
Пример использования
class Guides(TopicCatalog, topic_id='guides'):
pass
class Intermediate(Guides):
pass
class Intro(Intermediate, topic_id='intro'):
pass
class API(TopicCatalog, topic_id='api'):
pass
class APIIntro(API, topic_id='intro'):
pass
print(Intro.path)
print(APIIntro.path)
print(TopicCatalog.catalog[Intro.path] is Intro)
Вывод:
docs/guides/intro docs/api/intro True
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Связанные задачи
- Когда вызывается initsubclass в Python: тест
- Метаклассы Python: передача аргументов класса в initsubclass
- Python initsubclass: запрет переопределения констант
- Метакласс Python: регистрация методов в пространстве имён
- Python initsubclass: проверка порядка миграций схемы
- MRO в Python: проверка порядка примесей в наследовании
