Вопрос проверяет понимание механизма доступа к атрибутам в Python и различий между пользовательским вызовом и внутренним перехватом.
getattr(obj, name) — это функция, которая пытается получить атрибут по имени и может вернуть значение по умолчанию. __getattribute__ — это метод, который вызывается при любом доступе к атрибуту через точку, и он перехватывает весь механизм. Ошибка в __getattribute__ легко приводит к бесконечной рекурсии. Обычно для кастомной логики чаще используют __getattr__, а не __getattribute__.
getattr(obj, name[, default]) — это удобная функция для динамического доступа к атрибуту по строке:
x = getattr(user, "name", "unknown")
__getattribute__(self, name) — специальный метод, который Python вызывает всегда, когда вы делаете:
value = obj.attr
То есть obj.attr превращается в вызов obj.__getattribute__("attr").
Различие концептуальное:
getattr — это «внешний» инструмент, который использует стандартный механизм доступа
__getattribute__ — это «внутренний крючок», который определяет, как вообще работает доступ к атрибутам
Упрощённо Python делает так:
вызывает __getattribute__(name)
внутри стандартной реализации ищет атрибут в:
данных экземпляра (obj.__dict__)
классе и его родителях
дескрипторах (например, @property)
если не найдено — может быть вызван __getattr__(name) (если определён)
Важно: __getattr__ вызывается только когда атрибут не найден обычным способом, а __getattribute__ — всегда.
Если внутри __getattribute__ обратиться к self.some_attr, вы снова вызовете __getattribute__, и так по кругу. Поэтому используют базовую реализацию:
class A:
def __init__(self):
self.x = 10
def __getattribute__(self, name):
# логирование доступа (пример)
# print("access", name) # опционально
return object.__getattribute__(self, name)
Если нужно подменять поведение, обычно делают аккуратно:
class A:
def __getattribute__(self, name):
if name == "secret":
return "***"
return object.__getattribute__(self, name)
getattr применяют, когда:
имя атрибута известно только во время выполнения
нужно безопасное значение по умолчанию
__getattribute__ применяют редко, в продвинутых случаях:
прокси-объекты и ленивые вычисления
динамические модели, где атрибуты «виртуальные»
централизованное логирование/трассировка доступа
getattr — это удобная функция для динамического доступа, а __getattribute__ — низкоуровневый перехватчик любого обращения к атрибутам. В реальных проектах __getattribute__ используют осторожно и почти всегда через object.__getattribute__, чтобы избежать рекурсии.