What is the difference between __getattr__ and __getattribute__?
`__getattribute__` and `__getattr__` are both attribute access hooks, but they differ fundamentally in when they are called and how dangerous they are to override.
**`__getattribute__`** is called on *every* attribute access—`obj.x` unconditionally invokes `type(obj).__getattribute__(obj, 'x')`. It's the lowest-level hook in Python's attribute lookup machinery. Overriding it gives you total control over attribute resolution. The danger: any attribute access inside `__getattribute__` itself (including `self.anything`) recursively calls `__getattribute__` again, causing infinite recursion unless you bypass it with `object.__getattribute__(self, name)`. This makes it very easy to write buggy code. Override it only when you need to intercept all attribute access—e.g., read-tracking, transparent proxies, ORM query builders.
**`__getattr__`** is called only when the normal attribute lookup chain fails—i.e., the attribute wasn't found in the instance's `__dict__`, the class, or any base class. It's a fallback hook, not an interception hook. This makes it safe and idiomatic: overriding it adds dynamic attribute behavior without interfering with normal attributes.
Common use cases for `__getattr__`: providing dynamic attributes based on naming conventions (e.g., `obj.get_field_name()` on a dynamic schema), lazy-loading expensive attributes, implementing proxy objects that forward attribute accesses to a wrapped object, and fluent builder patterns.
Example:
```python class DynamicProxy: def __init__(self, target): object.__setattr__(self, '_target', target) # bypass __setattr__ def __getattr__(self, name): # only called if normal lookup fails return getattr(self._target, name) ```
Note: even setting `self._target` in `__init__` must use `object.__setattr__` if you've also overridden `__setattr__`, or you risk infinite recursion.
The lookup order matters: `__getattribute__` → instance `__dict__` → class `__dict__` → base class MRO → `__getattr__`. Raising `AttributeError` inside `__getattribute__` triggers `__getattr__` as a fallback.
Correctly states __getattribute__ intercepts all access while __getattr__ is a fallback, explains infinite recursion risk in __getattribute__, gives a use case for __getattr__.
Explains the full attribute lookup order, explains how to safely access self inside __getattribute__ using object.__getattribute__, gives a concrete proxy example, and explains how AttributeError in __getattribute__ triggers __getattr__.
Reading the answer is step one. Explaining it unprompted — under interview pressure — is what actually matters. Get AI-graded feedback on your answer with follow-up probes on your weak points.
Get Graded — Free Assessment