Чем __getattr__ отличается от __getattribute__?
- Как перехватить обращение к несуществующему атрибуту?
__getattribute__ вызывается при каждом обращении к атрибуту — это сам механизм поиска. __getattr__ вызывается только если атрибут не найден обычным путём. Для прокси, ленивых атрибутов и обёрток используют __getattr__ — он безопаснее и дешевле.
- В __getattribute__ легко получить бесконечную рекурсию — обращаться через object.__getattribute__(self, name)
- __getattr__ должен бросать AttributeError для неизвестных имён
- Модуль тоже может иметь __getattr__ (PEP 562) — ленивый импорт, предупреждения об устаревании
А ещё Пара для записи — __setattr__ и __delattr__
Подробно
__getattribute__ — точка входа всякого obj.name. Реализация по умолчанию (object.__getattribute__) выполняет поиск: дескрипторы данных, словарь экземпляра, атрибуты класса. Переопределяют редко — для отладки, контроля доступа. Любое self.x внутри снова вызывает __getattribute__ — рекурсия; обращаются через super() или object.__getattribute__(self, name).
__getattr__ — запасной путь: вызывается, когда обычный поиск бросил AttributeError. Подходит для:
- прокси и обёрток — делегировать всё неизвестное обёрнутому объекту;
- динамических атрибутов — API-клиент, где
client.usersстроит запрос; - ленивой загрузки.
Важно бросать AttributeError для неизвестных имён: иначе ломаются hasattr, getattr с умолчанием, pickle и copy.
Модульный __getattr__ (PEP 562): функция __getattr__(name) на уровне модуля вызывается для отсутствующих имён — ленивый импорт тяжёлых подмодулей, предупреждение об устаревших именах.
Пример
class Proxy:
def __init__(self, target):
self._target = target
def __getattr__(self, name): # только для отсутствующих
print("доступ к", name)
return getattr(self._target, name)Что хотят услышать
- Когда вызывается каждый.
- Риск рекурсии.
- Типичные применения.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✓__getattribute__ — при каждом обращении, __getattr__ — если атрибут не найден
- ✗__getattr__ вызывается при каждом обращении, а __getattribute__ — только если атрибут не найден
- ✗__getattribute__ — безопасный выбор для прокси-объектов: в нём невозможно уйти в рекурсию
- ✗__getattr__ должен возвращать None, если атрибута нет, а не бросать AttributeError
Разбор темы
- Модель данных — создание объектов, атрибуты и дескрипторы
__new__ и __init__, согласование __eq__ и __hash__, __getattr__ и __getattribute__, дескрипторы и __slots__.
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.