Дескриптор Python: однократная запись и setname
Напишите решение на Python и проверьте его на странице.
Другие упражнения по этой теме: Дескрипторы Python: задачи на get, set и set_name.
Регистры однократной записи
В прошивке промышленного контроллера калибровочные коэффициенты разрешено задавать ровно один раз при включении стенда. Защиту таких настроек берёт на себя специальный data-дескриптор, который автоматически связывается с именем управляемого атрибута через __set_name__.
При первом присваивании дескриптор проверяет тип переданного значения и сохраняет его в локальном хранилище объекта. Любая повторная попытка перезаписать уже установленный регистр в том же экземпляре должна немедленно вызывать ValueError, оставляя прежнее значение нетронутым. Если же значение регистра попытаются прочесть до первой записи, обращение завершается стандартным AttributeError. При доступе к атрибуту через сам класс возвращается непосредственно объект-дескриптор.
Реализуйте валидирующий дескриптор однократной записи, обеспечивающий такое поведение регистров.
Что уже дано
В редакторе объявлен класс WriteOnce с заготовками методов __init__, __set_name__, __get__ и __set__. Вспомогательные функции для тестирования протокола доступны во время исполнения скрипта, реализовывать их заново не требуется.
Что нужно сделать
Реализуйте data-дескриптор WriteOnce(expected_type: type):
- Конструктор принимает тип
expected_type, которому обязаны соответствовать записываемые значения. - Метод
__set_name__(self, owner, name)автоматически сохраняет имя поля при связывании с классом-владельцем. - До первого успешного присваивания атрибут считается неинициализированным в каждом объекте-владельце независимо. Чтение неинициализированного атрибута через экземпляр возбуждает
AttributeError. - При первом присваивании дескриптор проверяет тип:
isinstance(value, self.expected_type). Если передан неподходящий тип, возбуждаетсяTypeError, а атрибут остаётся неинициализированным. - После первого успешного присваивания любая последующая попытка записать новое значение в тот же экземпляр возбуждает
ValueError(даже если тип нового значения неверен), а исходное сохранённое значение не меняется. - Ложные по булевой логике значения (
0,False, пустые строки, коллекции иNone) являются полноценными корректными значениями, если они удовлетворяютexpected_type. - При обращении к атрибуту через класс-владелец (
instance is None) метод__get__возвращает сам объект-дескрипторself. - Разные атрибуты одного класса и независимые экземпляры класса не должны делить значения между собой.
Ввод и вывод
Потоки stdin и stdout не используются: считывать ввод и вызывать print() не нужно. Тестирующая система извлекает класс верхнего уровня WriteOnce после выполнения кода ученика и проверяет его поведение на классах-владельцах с 1–10 дескрипторами, сериями из 1–100 объектов и до 1000 операций в серии.
Пример использования
class Controller:
gain = WriteOnce(int)
controller = Controller()
try:
print(controller.gain)
except AttributeError:
print("AttributeError")
controller.gain = 7
print(controller.gain)
try:
controller.gain = 9
except ValueError:
print("ValueError")
print(controller.gain)
Вывод:
AttributeError 7 ValueError 7
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Связанные задачи
- Дескриптор и dict в Python: кто имеет приоритет при чтении
- Дескрипторы Python: почему значение разделяется между экземплярами
- Дескрипторы Python: валидация и сброс кэша зависимых свойств
- Дескрипторы Python: значения по умолчанию и удаление переопределений
- Дескриптор Python: проверка связанных полей low и high
- Дескриптор Python без get: журнал присваиваний в set
