
Атрибуты объекта в Python – это именованные поля (данные, функции), присущие данному объекту (экземпляру, классу). Самый простой доступ к атрибутам – через точку:
class Foo: def init(self): self.x = 88 # установка значения атрибута f = Foo() print(f.x) # доступ к атрибуту через точку
Если мы обратимся к атрибуту, которого нет, то получим ошибку AttributeError
. Мы можем переопределить это поведение путем реализации магических методов __getattr__
или __getattribute__
.
__getattr__
вызывается, если атрибут не найден обычным способом (не был задан ранее через точку, функцию setattr
, или через __dict__
). Если атрибут найден, то __getattr__
НЕ вызывается.
📎 Пример. Возвращаем -1 для любого несуществующего атрибута.
class Test: def __getattr__(self, item): print(f'__getattr__({item})') return -1 t = Test() # зададим x и y t.x = 10 setattr(t, 'y', 33) print(t.x) # 10 print(t.y) # 33 print(t.z) # __getattr__(z) -1
Метод __getattribute__
вызывается, когда мы пытаемся получить любой атрибут, не зависимо от того, есть он или нет. Этот метод, вызывается прежде __getattr__
. Он немного хитрее. Если __getattribute__
кидает AttributeError
, то будет вызвана __getattr__
.
📎 Пример. Мы можем запретить чтение каких-то атрибутов:
class Test: def __getattr__(self, item): print(f'__getattr__({item})') return -1 def __getattribute__(self, item): print(f'__getattribute__({item})') if item == 'y': # запретим получать y raise AttributeError return super().__getattribute__(item) # зададим x и y t = Test() t.x = 10 t.y = 20 print(t.x) # __getattribute__(x) 10 print(t.y) # __getattribute__(y) __getattr__(y) -1 print(t.z) # __getattribute__(z) __getattr__(z) -1
⚠️ Внимание! В __getattribute__
мы можем вызвать super().__getattribute__(item)
или object.__getattribute__(self, item)
, что посути тоже самое, но не следует делать return self.__dict__[item]
или return self.__getattribute__(item
) или return getattr(self, item)
, так как это приведет к бесконечной рекурсии.
💡 Также есть магический метод __setattr__(self, key, value)
, вызываемый при obj.key = value
или setattr(obj, 'key', value)
. У него нет более длинно-названного брата-близнеца.
Для полноты картины еще есть встроенная функция getattr(object, name[, default])
. Вызов getattr(x, 'y')
аналогичен обращению через точку: x.y
В первом случае ‘y’ – это строка, что позволяет нам динамически получать атрибуты объектов, в отличие от точки, которая требует фиксированного имени на этапе написания кода. В случае, если атрибут недоступен мы получим AttributeError
при незаданном default
или получим default
(без возникновения ошибки), если default
был задан третьим аргументом.
Специально для канала @pyway.