Python

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.

August 2026 5 min read 13 views 0 hearts

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.something inside either method without using super()—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.

0 in thread

Join the discussion

Shown next to your comment.

Up to 4,000 characters

No comments yet

Be the first to leave a note — it helps the next reader.