Python __getattr__ vs __getattribute__: Key Differences
Learn the crucial difference between Python's __getattr__ and __getattribute__ magic methods, when to use each, and how to avoid infinite recursion and other common pitfalls.
Python's __getattr__ vs __getattribute__: When Magic Methods Behave Differently
You've probably used Python long enough to appreciate its magic methods. They make code cleaner, more Pythonic, and sometimes, just plain fun. But two of them—__getattr__ and __getattribute__—often cause confusion, even among experienced developers.
The difference isn't just academic. Choosing the wrong one can lead to subtle bugs, infinite recursion, or code that works fine until it doesn't.
Let's break down what each does, when to use which, and how PythonSkillset developers can avoid common pitfalls.
What They Have in Common
Both methods intercept attribute access on objects. When you write my_object.something, Python looks for that attribute through a chain. These methods let you customize that chain.
But the timing differs. And that changes everything.
The Difference in Simple Terms
__getattribute__runs first—every time—no matter what. It's called when any attribute is accessed, even if the attribute exists normally.__getattr__only runs as a fallback. It's called when the normal attribute lookup fails (AttributeError would be raised).
Think of __getattribute__ as the gatekeeper, and __getattr__ as the safety net.
Example That Makes It Concrete
class SkillsetUser:
def __init__(self, username):
self.username = username
def __getattribute__(self, name):
print(f"__getattribute__ called for '{name}'")
return super().__getattribute__(name)
def __getattr__(self, name):
print(f"__getattr__ called for '{name}'")
return f"Default for {name}"
user = SkillsetUser("pythonskillset")
print(user.username) # Calls __getattribute__, finds the attribute
print(user.avatar) # Calls __getattribute__, fails, then __getattr__
Output:
__getattribute__ called for 'username'
pythonskillset
__getattribute__ called for 'avatar'
__getattr__ called for 'avatar'
Default for avatar
See the flow? __getattribute__ runs for both. But when the attribute doesn't exist, Python falls through to __getattr__.
The Infinite Recursion Trap (Real Danger)
Here's where beginners (and sometimes pros) get burned:
class BadExample:
def __getattribute__(self, name):
return self.__dict__[name] # BAD! Calls __getattribute__ again
This crashes with recursion error. Why? self.__dict__ itself triggers __getattribute__, which tries to access self.__dict__, which... you see the loop.
To avoid this, always use super().__getattribute__(name) inside __getattribute__.
When to Use Each in Real Projects
Use __getattr__ When:
- You want to provide dynamic default values for missing attributes
- Building proxies, mocks, or fallback logic
- You don't want to slow down normal attribute access
Real example from PythonSkillset: A configuration object that falls back to environment variables.
class Config:
def __init__(self, settings_dict):
self._settings = settings_dict
def __getattr__(self, name):
# Fallback to environment variable if setting not found
import os
env_value = os.environ.get(name.upper())
if env_value:
return env_value
raise AttributeError(f"Config has no '{name}'")
Use __getattribute__ When:
- You need to intercept every attribute access, even existing ones
- Implementing access control, logging, or caching
- Creating descriptor-like behavior without descriptors
Real example: A read-only wrapper that prevents attribute modification.
class ReadOnlyObject:
def __init__(self, wrapped):
object.__setattr__(self, '_wrapped', wrapped)
def __getattribute__(self, name):
if name == '_wrapped':
return super().__getattribute__(name)
wrapped = super().__getattribute__('_wrapped')
return getattr(wrapped, name)
def __setattr__(self, name, value):
raise AttributeError("This object is read-only")
Performance Considerations
__getattribute__ runs on every attribute access. That means even simple operations like self.x += 1 call it multiple times (once to read, once to write). On performance-critical code, this overhead matters.
__getattr__ only runs when needed, so it's generally free for normal attribute access.
The Golden Rule for PythonSkillset Developers
- If you only need to handle missing attributes, use
__getattr__. - If you need to control all attribute access, use
__getattribute__. - Never call
self.somethinginside either method without usingsuper()—you'll create recursion. - Document your intent. These methods make code clever, but clever code without comments is just future debugging pain.
Understanding this difference separates Python developers who write code that works from those who write code that's maintainable and predictable. Both methods are powerful tools—just know which one you're reaching for.
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.