Осуществляйте контроль над атрибутами в вашем классе
Управляйте своими атрибутами
В этом руководстве будет показано, как просто создать атрибуты только для чтения и защиты от удаления в вашем классе Python. Таким образом, к вашим атрибутам может быть применен дополнительный уровень контроля, гарантирующий, что ваш класс используется по назначению. Хотя существует несколько способов создания атрибутов только для чтения и защиты от удаления в Python, использование методов setattr и delattr dunder - удобный способ быстрого управления атрибутами в ваших объектах.
Пример: класс сотрудников
Однократная установка атрибутов
Чтобы проиллюстрировать это, давайте представим, что мы создаем простой класс Employee, который требует, чтобы в объекте были установлены три значения. Этими значениями будут имя сотрудника, его возраст и его уникальный идентификационный номер. Эти значения атрибутов будут установлены в атрибутах; '_name', _'age', and '_id_number'
и обозначены подчеркиванием, чтобы указать, что они являются частными атрибутами, не предназначенными для использования вне класса.
После установки __init__
method необходимо определить магический метод __setattr__
. В этом методе мы можем применить некоторую простую логику для эффективного управления атрибутами. В представленном примере __init__
method вызывает __setattr__
method, когда атрибуты сначала устанавливаются во время инициализации объекта. Мы можем предотвратить сброс атрибута _name
, применив следующую логику.
Для этого мы можем написать условное выражение, которое говорит, что когда устанавливается новый атрибут, если атрибут равен _name
и уже имеет значение, тогда программа выйдет и вызовет встроенный AttributeError
exception с настраиваемым сообщением, отображаемым в стандартный вывод ошибок (stderr). Атрибут _name
устанавливается во время инициализации объекта, поэтому любой сброс этого атрибута вызовет исключение и завершит программу.
Мы также могли бы осуществить некоторый дополнительный контроль, убедившись, что атрибуты _age
и _id_number
имеют целочисленный тип. Мы можем создать список и проверить, что атрибуты _age
и _id_number
находятся в последнем, прежде чем мы установим их как целое число. Код для этого показан ниже в методе setattr.
Примечание. В показанных примерах, когда атрибут установлен, он устанавливается не с использованием синтаксиса object.attribute в магическом методе setattr, а с использованием object.__dict__[key] = value
. Если мы воспользуемся первым подходом, будет инициирован бесконечный рекурсивный цикл, потому что синтаксис object.attribute вызовет метод setattr!
Теперь давайте создадим объект Employee и проверим, установлены ли атрибуты. Как показано, атрибуты установлены и имеют правильный тип.
Теперь предположим, что мы хотели бы повторно установить атрибут _name
, несмотря на то, что он уже был установлен. В этом случае возникает AttributeError
exception и выводится сообщение на консоль, информирующее пользователя о том, что атрибут name был установлен и не может быть повторно установлен.
Атрибуты доказательства удаления
Чтобы защитить наш атрибут от удаления атрибута name, мы можем просто добавить некоторую логику к методу dunder delattr. Здесь мы говорим, что если пользователь попытается удалить имя атрибута из объекта, будет возбуждено исключение AttributeError
, информирующее пользователя о том, что атрибут name не может быть удален. Однако мы по-прежнему разрешаем поведение, которое позволяет пользователям удалять любой другой атрибут в объекте Employee.
Исключение AttributeError
exception теперь возникает, когда мы пытаемся удалить атрибут защищенного имени из объекта Employee, emp_1.
Бонус: индивидуальный информативный класс
В то время как AttributeError
class хорошо объясняет пользователю, почему программа завершилась, когда пользователь пытается удалить _name
attribute, причину можно сделать даже более явной за счет создания настраиваемого класса исключения.
Мы можем написать собственный DeletionException
class, который будет активирован, если пользователь попытается удалить атрибут _name
. Мы также можем с пользой сообщить пользователю, каков атрибут name в настоящее время, когда вызывается DeletionException
class. Это сообщение можно распечатать в стандартном выводе ошибок.
Для этого мы создаем DeletionException
class, который наследуется от базового класса Exception и принимает один аргумент, здесь исходное значение атрибута. Это значение устанавливается в DeletionException
object при создании экземпляра класса, например при его поднятии. Когда он поднимается, мы передаем исходный атрибут имени в качестве единственного аргумента в класс. Это происходит внутри __delattr__
метода.
При поднятии будет вызван метод __str__
, который распечатает сообщение, информирующее пользователя о том, что исходный атрибут name в объекте Employees не может быть удален.
Резюме
Методы dunder setattr и delattr могут быть изменены с помощью настраиваемой логики для защиты атрибутов и управления их доступом. Кроме того, могут быть добавлены настраиваемые классы исключений для полезного информирования пользователей о том, почему атрибуты защищены.