12. Аттрибуты объектов.
Работа с аттрибутами объектов
- По-умолчанию каждый объект имеет словарь полученный от своего класса, в котором хранятся поля объекта.
- Словарь доступен как
ObjectClass.__dict__
. - При чтении (value = obj.name) или записи (obj.name = value) по имени обращение автоматически происходит к объекту в словаре по ключу name.
- Поведение при работе с аттрибутами объекта (полями, доступными по имени) можно переопределять.
Переопределение доступа к полям по имени
__getattr__(self, name)
- переопределить доступ к аттрибуту (a = x.name) при попытке чтения.- Вызывается только тогда, когда не удалось найти аттрибут обычными способами (не является полем текущего объекта или какого-либо класса в иерархии предков).
- Должен либо вернуть сформированное значение по указанному имени, либо вызвать AttributeError.
- Важно: используется только, если поле не найдено по имени другим способом.
__setattr__(self, name, value)
- при попытке записи данных в аттрибут (x.name = a).- Вызывается при попытке присваивания, перекрывает обычный механизм присваивания (в отличие от
__getattr__
). - Для присваивания аттрибута текущему объекту над вызвать
__setattr__()
у базового класса (self.name = value не сработает). - Важно: в отличие от предыдущего
__getattr__
перекрывает стандартный механизм.
- Вызывается при попытке присваивания, перекрывает обычный механизм присваивания (в отличие от
__delattr__(self, name)
- удалить аттрибут по имени.- Реализовывать стоит только в том случае, если del x.name имеет смысл для текущего объекта.
__getattribute__(self, name)
- переопределить доступ к аттрибуту при чтении (для new-style classes).- Подобен
__getattr__
, но в отличие от него перекрывает обычный механизм безусловно. - В случае, если также определён
__getattr__
, то последний вызовется только если его явно вызвать из__getattribute__
или бросить исключение AttributeError в__getattribute__
. - Для получения аттрибута у текущего объекта, во избежание рекурсии, надо вызывать
__getattribute__
у базового класса.
- Подобен
Определение property полей
Декоратор property позволяет определять виртуальные поля, задавая (или нет) отдельные методы в качестве геттера, сеттера, удаляющего, а также определить документацию.
class PseudoMeter(object): def __init__(self): self.__temperature = 0 def __get_temperature(self): print "Asked for temperature" return self.__temperature def __set_temperature(self, value): print "Got new value" if not isinstance(value, int): raise TypeError("int value required") self.__temperature = value temperature = property(__get_temperature, __set_temperature) meter = PseudoMeter() meter.temperature = 10 print meter.temperature
Got new value Asked for temperature 10
Это был простейший пример. Можно делать аккуратнее и, зависимости от конкретного случая, использовать данный декоратор различными способами.
class PseudoMeter(object): def __init__(self): self.__temperature = 0 @property def temperature(self): print "Asked for temperature" return self.__temperature meter = PseudoMeter() print meter.temperature
Asked for temperature 0
Или так:
class PseudoMeter(object): def __init__(self): self.__temperature = 0 @property def temperature(self): print "Asked for temperature" return self.__temperature @temperature.setter def temperature(self, value): print "Got new value" if not isinstance(value, int): raise TypeError("int value required") self.__temperature = value meter = PseudoMeter() meter.temperature = 10 print meter.temperature
Got new value Asked for temperature 10