Python's `__getattr__` vs `__getattribute__`: When to Use Each One
Learn the key difference between Python's `__getattribute__` (called on every attribute access) and `__getattr__` (called only when lookup fails), with real-world examples and common pitfalls.
If you've been working with Python long enough, you've probably stumbled upon those double-underscore methods that control how objects access their attributes. Two of the most confusing ones are __getattr__ and __getattribute__. They sound similar, they do similar things, but they work in fundamentally different ways.
I've seen many developers at PythonSkillset.com mix them up, and honestly, it's easy to do. Let me break down exactly when you'd use each one.
The Quick Version
__getattribute__ is called every single time you access any attribute on an object. __getattr__ is only called when the normal attribute lookup fails.
That's it. That's the core difference. But let's dive deeper because this distinction matters a lot in real code.
How __getattribute__ Works
When Python sees obj.anything, it first calls __getattribute__. If that method raises an AttributeError, then Python falls back to __getattr__. But here's the catch—__getattribute__ runs for every attribute access, even for methods and dunder methods.
Let me show you a simple example:
class DataWrapper:
def __init__(self, data):
self.data = data
def __getattribute__(self, name):
print(f"Accessing {name}")
return super().__getattribute__(name)
wrapper = DataWrapper([1, 2, 3])
print(wrapper.data) # Prints: Accessing data, then [1, 2, 3]
print(wrapper.nonexistent) # AttributeError: 'DataWrapper' object has no attribute 'nonexistent'
Notice how __getattribute__ runs even for wrapper.data. That's why it's powerful but dangerous—you have to be careful not to create infinite recursion.
When __getattr__ Kicks In
__getattr__ only gets called when __getattribute__ fails to find the attribute. This makes it safer for most use cases:
class FallbackConfig:
def __init__(self):
self.actual_settings = {'host': 'localhost', 'port': 8080}
def __getattr__(self, name):
if name in self.actual_settings:
return self.actual_settings[name]
raise AttributeError(f"Config has no {name}")
config = FallbackConfig()
print(config.host) # 'localhost'
print(config.port) # 8080
print(config.timeout) # AttributeError
Here, config.host works because __getattr__ intercepts the failed lookup. But if you had set config.host = 'example.com' earlier, that attribute would be found normally and __getattr__ wouldn't run.
Real-World Use Cases at PythonSkillset
When to Use __getattribute__
Use this when you need to intercept every attribute access. For example:
- Access control – logging, permission checks, or attribute monitoring
- Property mocking – replacing the default behavior for attribute access
- Dynamic attribute systems – where attribute names are determined at runtime
Here's a practical example from a logging decorator:
class LoggedObject:
def __init__(self, wrapped):
self._wrapped = wrapped
def __getattribute__(self, name):
if name in ['_wrapped', '__class__']:
return super().__getattribute__(name)
print(f"Accessing {name} on {self._wrapped}")
return getattr(self._wrapped, name)
When to Use __getattr__
Use this when you want to provide defaults or handle missing attributes gracefully:
- Configuration objects – like the config example above
- Proxy objects – delegating to another object
- Lazy initialization – generating attributes on first access
- Fallback data sources – checking multiple locations
A lazy-loading example that many PythonSkillset users appreciate:
class LazyConfig:
def __init__(self, config_path):
self._config_path = config_path
self._loaded = False
self._data = {}
def __getattr__(self, name):
if not self._loaded:
self._load_config()
if name in self._data:
return self._data[name]
raise AttributeError(f"Unknown config: {name}")
def _load_config(self):
# Simulate reading config file
self._data = {'db_host': 'localhost', 'db_port': 5432}
self._loaded = True
The Gotchas You'll Encounter
Infinite Recursion Danger
This is the most common pitfall. In __getattribute__, if you try to access an attribute using self.attribute, it calls __getattribute__ again, creating a loop:
# DON'T DO THIS
class Broken:
def __getattribute__(self, name):
return self._value # Recursion! This calls __getattribute__ again
# DO THIS INSTEAD
class Working:
def __getattribute__(self, name):
return object.__getattribute__(self, '_value') # Safe
hasattr() Behavior
hasattr() works by trying to access the attribute and catching AttributeError. With __getattr__, hasattr(obj, 'something') will return True if __getattr__ doesn't raise an error.
class AlwaysHas:
def __getattr__(self, name):
return "I exist!"
obj = AlwaysHas()
print(hasattr(obj, 'anything')) # True
print(hasattr(obj, 'something_else')) # True
This can lead to surprising behavior if you're not careful.
Chaining and Method Access
Both methods affect how methods work too. If you override __getattribute__, even calling obj.method() goes through it. That's why you must handle method attributes carefully.
Which One Should You Use?
Here's my rule of thumb:
- Use
__getattr__for 90% of cases where you need custom attribute access - Use
__getattribute__only when you must intercept attribute lookups even for existing attributes
__getattr__ is simpler, safer, and what most Python libraries actually use under the hood. __getattribute__ is more powerful but comes with more responsibility.
At PythonSkillset, we've seen both methods used effectively in production. The key is understanding the difference and knowing which behavior your application needs. Start with __getattr__ and only reach for __getattribute__ when you truly need it.
Comments
Questions, corrections, and tips stay visible for everyone reading this page.
Join the discussion
No comments yet
Be the first to leave a note — it helps the next reader.