Метакласс Python: регистрация методов в пространстве имён
Напишите решение на Python и проверьте его на странице.
Другие упражнения по этой теме: Метаклассы и init_subclass Python: задачи на проверку классов.
Пространство командных методов
Модульный интерфейс терминала позволяет классам-плагинам регистрировать свои методы действий в общем командном меню. Чтобы команды разных модулей не путались между собой, каждый плагин передаёт в заголовке ключевое слово namespace_prefix="имя", а сами целевые методы оформляет со стандартным префиксом do_.
За сборку таких классов отвечает метакласс. В своём методе __new__ он извлекает указанный namespace_prefix, перехватывает сырое пространство имён и преобразует имена команд: служебное do_ заменяется на заданный префикс со знаком подчёркивания, а исходный ключ с do_ удаляется. Если же получившееся целевое имя уже заранее объявлено в пространстве имён класса, метакласс не перезаписывает его, а немедленно прерывает создание класса исключением ValueError.
Реализуйте метакласс, который переименовывает методы действий по переданному префиксу и защищает класс от коллизий с уже существующими атрибутами.
Что уже дано
В редакторе объявлен класс CommandNamespace(type) с заготовкой метода __new__(mcs, name, bases, namespace, **kwargs).
При выполнении решения в среде также доступны готовые проверочные функции observe_command_declarations, inspect_prepared_command_class и observe_command_classcell для сборки тестовых классов и проверки цепочки вызовов. Реализовывать их заново не требуется.
Что нужно сделать
Реализуйте метод __new__(mcs, name, bases, namespace, **kwargs) метакласса CommandNamespace.
При создании класса соблюдайте следующие правила:
- Аргумент
namespace_prefixобязателен и явно передаётся при создании любого класса с этим метаклассом (непустая ASCII-строка длиной от 1 до 20 символов). Извлеките его изkwargsперед передачей параметров вtype.__new__. - Все остальные именованные аргументы заголовка класса должны быть переданы дальше без изменений для кооперативной работы с базовыми классами и хуком
__init_subclass__(например, аргументtag). - В сыром словаре пространства имён
namespaceнайдите все собственные ключи, начинающиеся сdo_и имеющие непустой суффикс (от 0 до 8 методов на класс). Каждое такое имя преобразуется вf"{namespace_prefix}_{suffix}". Исходный ключdo_...удаляется, а функция сохраняется под новым именем с сохранением исходного объекта и его привязки к экземпляру. - Если целевое имя уже присутствует в исходном словаре
namespace, немедленно возбудите исключениеValueError(или его подкласс) до вызова базового конструктора класса. Это правило распространяется и на случай, когда префикс равенdo, а целевое имя совпадает с другим уже существующим собственным ключомdo_.... - Проверяйте на коллизии только текущее сырое пространство имён
namespace. Атрибуты базовых классов конфликтом не считаются, а унаследованные методы не должны модифицироваться или переименовываться. - Обычные методы, константы (целые числа, логические значения, строки,
None), а также служебные атрибуты Python (включая__classcell__, необходимый для работыsuper()без аргументов) должны оставаться нетронутыми. - Конструктор должен сохранять переданный метакласс
mcs, чтобы поддерживать корректное наследование отCommandNamespace.
Ввод и вывод
Стандартные потоки ввода stdin и вывода stdout в решении не используются: считывать ввод и вызывать print() не нужно. После выполнения кода учащегося проверяющая система считывает из пространства имён модуля класс верхнего уровня CommandNamespace и использует его при создании тестовых классов.
Пример использования
class Build(metaclass=CommandNamespace, namespace_prefix='build'):
def do_run(self, value):
return value * 2
VERSION = 1
print(Build().build_run(7))
print('do_run' in vars(Build))
try:
class Conflict(metaclass=CommandNamespace, namespace_prefix='build'):
build_run = None
def do_run(self):
return 1
except ValueError:
print('ValueError')
Вывод:
14 False ValueError
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Связанные задачи
- Когда вызывается initsubclass в Python: тест
- Метаклассы Python: передача аргументов класса в initsubclass
- Python initsubclass: запрет переопределения констант
- Python initsubclass: проверка порядка миграций схемы
- MRO в Python: проверка порядка примесей в наследовании
- Метакласс Python: проверка парных методов prepare и render
