Python Custom Attribute Access
Learn how Python customizes instance attribute reads, fallback lookup, assignment, and deletion with __getattribute__, __getattr__, __setattr__, and __delattr__.
Advanced
Python lets a class customize what happens when code reads, writes, or deletes an attribute. The main hooks are
__getattribute__ for reads and
__setattr__ /
__delattr__ for writes and deletion. A separate
__getattr__ fallback runs only when normal lookup cannot find the requested attribute.
Intercept every instance attribute read
__getattribute__ is called for every instance attribute access. A common safe pattern is to let the base implementation perform the actual lookup after you add the behavior you need.
|
|
The hook runs for user.name, then object.__getattribute__() performs the normal lookup.
Avoid recursive lookup inside __getattribute__
Inside
__getattribute__, reading another attribute with ordinary dot syntax calls
__getattribute__ again. That can recurse forever. Use
object.__getattribute__(self, name) when you need the default lookup behavior.
|
|
The custom owner read uses the base lookup instead of self._owner, avoiding another intercepted lookup.
Use __getattr__ as a fallback
__getattr__ is different: it is called only after normal attribute access fails with
AttributeError. Existing attributes therefore continue through the normal mechanism.
|
|
theme is found normally; timeout is computed only after normal lookup fails.
Understand the order of both read hooks
When both hooks exist,
__getattribute__ runs first. If it raises
AttributeError and the class defines
__getattr__, Python can use the fallback. This makes the two hooks complementary rather than interchangeable.
|
|
The normal lookup fails first; the fallback then supplies the value.
Customize attribute assignment with __setattr__
__setattr__ is called when an instance attribute assignment is attempted. If you want the normal storage behavior, delegate to
object.__setattr__ rather than assigning with ordinary dot syntax inside the hook.
|
|
The hook validates the assignment and delegates accepted values to normal instance storage.
Customize attribute deletion with __delattr__
__delattr__ is called for
del obj.name. A custom implementation can enforce deletion rules and delegate the actual removal to
object.__delattr__.
|
|
Deleting session.token reaches the custom hook, which delegates to the normal deletion behavior.
Use getattr() when the attribute name is dynamic
The built-in
getattr() retrieves a named attribute without requiring dot syntax. Its optional default value is useful when a missing attribute should not raise
AttributeError. Custom attribute hooks still participate in the lookup.
|
|
getattr() works with names stored in variables or supplied dynamically, while the third argument supplies a fallback value.
Choose the smallest hook that solves the problem
Use
__getattr__ when you only need fallback behavior for missing attributes. Use
__getattribute__ when you genuinely need to control every instance read. Use
__setattr__ or
__delattr__ when assignment or deletion itself needs custom rules. In each hook, delegate to the base implementation when you want normal object behavior.
Know the special-method lookup boundary
Custom attribute access is not a universal interception layer for Python. The data model documents cases where implicit special-method lookup can bypass an instance’s
__getattribute__ machinery. This matters when debugging why a built-in operation does not produce the same trace as an explicit attribute lookup.
Key takeaways
- `__getattribute__` is the instance-level hook for attribute reads and runs before normal lookup returns a value.
- `__getattr__` is a fallback used only when normal attribute lookup raises AttributeError.
- Use object.__getattribute__() inside a custom getter when you need the default lookup without recursive interception.
- Use `__setattr__` and `__delattr__` to customize attribute assignment and deletion, delegating to the base implementation for normal storage behavior.
- Choose the narrowest hook that matches the requirement; broad interception adds complexity and can affect many ordinary attribute operations.
Thanks for your feedback.
Mark this learning resource complete to track your learning progress.