Дескриптор Python без get: журнал присваиваний в set

Напишите решение на Python и проверьте его на странице.

Другие упражнения по этой теме: Дескрипторы Python: задачи на get, set и set_name.

Односторонний журнал статусов

Модуль мониторинга безопасности принимает сообщения о состоянии защищённого хранилища через простое присваивание в атрибут status. За этим атрибутом стоит необычный data-дескриптор: он определяет метод __set__, но в нём намеренно отсутствует __get__. Каждая корректная непустая строка сразу отправляется в закрытый список истории конкретного экземпляра хранилища. Если же передать пустую строку или значение неподходящего типа, операция немедленно завершается ошибкой ValueError, а уже накопленный список записей остаётся нетронутым.

Поскольку у дескриптора нет собственного метода чтения, стандартный протокол Python ведёт себя особым образом. При обычной попытке прочесть status через точку интерпретатор заглядывает в словарь экземпляра: пока ключа 'status' там нет, чтение возвращает сам объект-дескриптор, закреплённый за классом. Если же записать значение с ключом 'status' напрямую в словарь экземпляра, то последующее чтение вернёт именно его.

Реализуйте этот односторонний механизм валидации и выясните, как именно меняется результат обращения к атрибуту status до и после прямой записи в словарь экземпляра.

Что уже дано

В редакторе представлена заготовка класса StatusHistory с нереализованным методом __set__(self, instance, value).

Вспомогательная функция observe_set_only_history уже доступна в окружении выполнения для тестирования сценариев и не требует самостоятельной реализации.

Что нужно сделать

Реализуйте класс StatusHistory со следующими требованиями:

  • Класс определяет метод __set__(self, instance, value) и намеренно не определяет и не наследует метод __get__.
  • Дескриптор принимает в качестве value только непустые строки (включая строки из подклассов str и строки, состоящие только из пробельных символов). Длина сообщений — от 0 до 1000 символов.
  • Любые некорректные значения (пустая строка "", а также значения любых типов, не принадлежащих семейству str) вызывают исключение семейства ValueError.
  • При возникновении ошибки список истории экземпляра не должен изменяться, а если валидных записей для этого объекта ещё не было — атрибут истории не должен создаваться преждевременно.
  • Каждое принятое сообщение добавляется в конец списка истории конкретного экземпляра instance по закрытому имени _status_history. Сам список _status_history создаётся только при первом успешном присваивании валидного значения.
  • Метод __set__ ни при каких условиях не должен создавать, изменять или удалять ключ 'status' в словаре instance.__dict__.
  • Истории различных экземпляров (включая объекты подклассов владельца) изолированы друг от друга: дескриптор не ведёт общего межэкземплярного состояния.
  • Количество операций присваивания и чтения в тестовых сценариях составляет от 0 до 1000.

Ввод и вывод

Стандартные потоки ввода stdin и вывода stdout в решении не используются: считывать ввод и вызывать print() не нужно. После выполнения кода учащегося проверяющая система считывает из пространства имён модуля класс верхнего уровня StatusHistory и вызывает его с проверочными аргументами.

Пример использования

class Storage:
    status = StatusHistory()

item = Storage()
print(item.status is Storage.status)
item.status = 'ready'
item.__dict__['status'] = 'shadow'
item.status = 'safe'
print(item.status, item._status_history)

Вывод:

True
shadow ['ready', 'safe']
РешениеPython

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

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

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