Python initsubclass: запрет переопределения констант
Напишите решение на Python и проверьте его на странице.
Другие упражнения по этой теме: Метаклассы и init_subclass Python: задачи на проверку классов.
Защита констант от переопределения
Каркас биллинговой системы задаёт базовые классы финансовых транзакций, в которых зафиксированы системные константы вроде идентификатора валюты расчёта или версии схемы. Разработчики конкретных платежных шлюзов могут расширять эти классы собственными полями и методами, но переопределять унаследованные базовые константы им запрещено.
Чтобы предотвратить случайные ошибки и скрытые конфликты имён, проверка выполняется прямо в момент создания нового класса. Специальный хук инициализации подклассов просматривает собственный словарь атрибутов объявленного наследника. Если потомок пытается задать у себя атрибут с именем, входящим в кортеж PROTECTED_CONSTANTS любого из его прямых или вышестоящих базовых классов, процесс создания немедленно прерывается вызовом TypeError.
Реализуйте базовый класс с хуком инициализации подклассов, который защитит константы предков от перекрытия в классах-наследниках.
Что уже дано
В заготовке объявлен базовый класс ProtectedConstants с пустым кортежем PROTECTED_CONSTANTS = () и заготовкой хука __init_subclass__.
Что нужно сделать
Реализуйте хук __init_subclass__(cls, **kwargs) в классе ProtectedConstants.
Правила проверки подклассов при их создании:
- Хук проверяет собственное пространство имён создаваемого класса (
cls). Если в нём объявлен атрибут, имя которого содержится в кортежеPROTECTED_CONSTANTSлюбого из его прямых или более далёких предков, создание класса должно быть отклонено исключениемTypeError(допускаются также его подклассы). Текст сообщения исключения не регламентируется. - Проверка затрагивает всех предков класса, включая ветви множественного наследования и стандартные примеси (mixins).
- Защищёнными считаются имена, задекларированные в
PROTECTED_CONSTANTSпредков. Сам создаваемый класс может одновременно объявить новые имена в собственном кортежеPROTECTED_CONSTANTSи задать для них значения: на этапе создания этого класса они ещё не считаются защищёнными предками. - Простое наследование константы без её объявления в теле подкласса разрешено. Если же имя объявлено в самом подклассе, это считается переопределением независимо от значения: установка того же самого значения, ложного значения (
None,False,0,"") или объявление метода с таким именем должно вызыватьTypeError. - Собственный пустой или дополненный кортеж
PROTECTED_CONSTANTSу подкласса не должен отменять защиту, заданную предками выше по иерархии. - Обычные незащищённые поля и методы разрешено свободно объявлять и переопределять.
- Сам атрибут
'PROTECTED_CONSTANTS'также может быть включён в список защищённых имён родительского класса. - Защита проверяется строго в момент создания класса через
__init_subclass__. Перехватывать последующее присваивание атрибутов у уже созданного класса или гарантировать физическую неизменяемость не требуется. - Не забудьте передать необработанные аргументы
**kwargsдальше по цепочке инициализации черезsuper().__init_subclass__(**kwargs).
Ограничения проверяемых сценариев:
- Количество попыток создания классов в рамках одного запуска: от 0 до 512.
- Глубина наследования: от 1 до 8 уровней; количество прямых родителей: от 1 до 3.
- Число защищённых имён в одной декларации: от 0 до 8.
- Имена классов и атрибутов представляют собой ASCII-идентификаторы длиной до 40 символов.
- Значения полей констант — целые числа (от -1 000 000 до 1 000 000), строки длиной до 40 символов,
boolилиNone; методы — обычные методы экземпляра. - В тестах гарантируется корректный порядок разрешения методов (MRO), отсутствие кастомных метаклассов, собственных переопределений
__init_subclass__в наследниках, слотов (__slots__), дескрипторов и служебных dunder-атрибутов.
Ввод и вывод
Стандартные потоки stdin и stdout не используются: считывать ввод и вызывать print в решении не требуется.
Тестирующая система выполняет код решения и получает из пространства имён класс верхнего уровня ProtectedConstants, после чего объявляет его подклассы в проверяющих тестах.
Пример использования
class Transaction(ProtectedConstants):
PROTECTED_CONSTANTS = ('CURRENCY',)
CURRENCY = 'RUB'
class Gateway(Transaction):
TIMEOUT = 30
print(Gateway.CURRENCY, Gateway.TIMEOUT)
try:
class InvalidGateway(Transaction):
CURRENCY = 'USD'
except TypeError:
print('TypeError')
Вывод:
RUB 30 TypeError
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Связанные задачи
- Когда вызывается initsubclass в Python: тест
- Метаклассы Python: передача аргументов класса в initsubclass
- Метакласс Python: регистрация методов в пространстве имён
- Python initsubclass: проверка порядка миграций схемы
- MRO в Python: проверка порядка примесей в наследовании
- Метакласс Python: проверка парных методов prepare и render
