Осуществляйте контроль над атрибутами в вашем классе

Управляйте своими атрибутами

В этом руководстве будет показано, как просто создать атрибуты только для чтения и защиты от удаления в вашем классе Python. Таким образом, к вашим атрибутам может быть применен дополнительный уровень контроля, гарантирующий, что ваш класс используется по назначению. Хотя существует несколько способов создания атрибутов только для чтения и защиты от удаления в Python, использование методов setattr и delattr dunder - удобный способ быстрого управления атрибутами в ваших объектах.

Пример: класс сотрудников

Однократная установка атрибутов

Чтобы проиллюстрировать это, давайте представим, что мы создаем простой класс Employee, который требует, чтобы в объекте были установлены три значения. Этими значениями будут имя сотрудника, его возраст и его уникальный идентификационный номер. Эти значения атрибутов будут установлены в атрибутах; '_name', _'age', and '_id_number'и обозначены подчеркиванием, чтобы указать, что они являются частными атрибутами, не предназначенными для использования вне класса.

После установки __init__method необходимо определить магический метод __setattr__. В этом методе мы можем применить некоторую простую логику для эффективного управления атрибутами. В представленном примере __init__method вызывает __setattr__method, когда атрибуты сначала устанавливаются во время инициализации объекта. Мы можем предотвратить сброс атрибута _name, применив следующую логику.

Для этого мы можем написать условное выражение, которое говорит, что когда устанавливается новый атрибут, если атрибут равен _name и уже имеет значение, тогда программа выйдет и вызовет встроенный AttributeErrorexception с настраиваемым сообщением, отображаемым в стандартный вывод ошибок (stderr). Атрибут _name устанавливается во время инициализации объекта, поэтому любой сброс этого атрибута вызовет исключение и завершит программу.

Мы также могли бы осуществить некоторый дополнительный контроль, убедившись, что атрибуты _age и _id_number имеют целочисленный тип. Мы можем создать список и проверить, что атрибуты _age и _id_number находятся в последнем, прежде чем мы установим их как целое число. Код для этого показан ниже в методе setattr.

Примечание. В показанных примерах, когда атрибут установлен, он устанавливается не с использованием синтаксиса object.attribute в магическом методе setattr, а с использованием object.__dict__[key] = value. Если мы воспользуемся первым подходом, будет инициирован бесконечный рекурсивный цикл, потому что синтаксис object.attribute вызовет метод setattr!

Теперь давайте создадим объект Employee и проверим, установлены ли атрибуты. Как показано, атрибуты установлены и имеют правильный тип.

Теперь предположим, что мы хотели бы повторно установить атрибут _name, несмотря на то, что он уже был установлен. В этом случае возникает AttributeErrorexception и выводится сообщение на консоль, информирующее пользователя о том, что атрибут name был установлен и не может быть повторно установлен.

Атрибуты доказательства удаления

Чтобы защитить наш атрибут от удаления атрибута name, мы можем просто добавить некоторую логику к методу dunder delattr. Здесь мы говорим, что если пользователь попытается удалить имя атрибута из объекта, будет возбуждено исключение AttributeError, информирующее пользователя о том, что атрибут name не может быть удален. Однако мы по-прежнему разрешаем поведение, которое позволяет пользователям удалять любой другой атрибут в объекте Employee.

Исключение AttributeErrorexception теперь возникает, когда мы пытаемся удалить атрибут защищенного имени из объекта Employee, emp_1.

Бонус: индивидуальный информативный класс

В то время как AttributeErrorclass хорошо объясняет пользователю, почему программа завершилась, когда пользователь пытается удалить _nameattribute, причину можно сделать даже более явной за счет создания настраиваемого класса исключения.

Мы можем написать собственный DeletionExceptionclass, который будет активирован, если пользователь попытается удалить атрибут _name. Мы также можем с пользой сообщить пользователю, каков атрибут name в настоящее время, когда вызывается DeletionExceptionclass. Это сообщение можно распечатать в стандартном выводе ошибок.

Для этого мы создаем DeletionExceptionclass, который наследуется от базового класса Exception и принимает один аргумент, здесь исходное значение атрибута. Это значение устанавливается в DeletionExceptionobject при создании экземпляра класса, например при его поднятии. Когда он поднимается, мы передаем исходный атрибут имени в качестве единственного аргумента в класс. Это происходит внутри __delattr__ метода.

При поднятии будет вызван метод __str__, который распечатает сообщение, информирующее пользователя о том, что исходный атрибут name в объекте Employees не может быть удален.

Резюме

Методы dunder setattr и delattr могут быть изменены с помощью настраиваемой логики для защиты атрибутов и управления их доступом. Кроме того, могут быть добавлены настраиваемые классы исключений для полезного информирования пользователей о том, почему атрибуты защищены.