Python
Object-Oriented Programming
__getattr__
__getattribute__
Python Attributes

Understanding the difference between __getattr__ and __getattribute__

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

__getattr__ and __getattribute__ both participate in attribute lookup, but they do very different jobs. The short version is: __getattribute__ runs for every attribute access, while __getattr__ is only a fallback for attributes that were not found normally.

That difference is crucial because __getattribute__ is powerful but easy to break, while __getattr__ is much safer for most dynamic behavior.

__getattr__ Is a Fallback

Python calls __getattr__(self, name) only after normal attribute lookup fails.

Example:

python
1class Config:
2    def __init__(self):
3        self.host = "localhost"
4
5    def __getattr__(self, name):
6        if name == "port":
7            return 5432
8        raise AttributeError(name)
9
10
11cfg = Config()
12print(cfg.host)
13print(cfg.port)

Output:

python
localhost
5432

host is found normally, so __getattr__ is not involved. port is missing, so Python falls back to __getattr__.

This makes __getattr__ a good fit for:

  • computed defaults
  • lazy attribute creation
  • wrappers and proxies
  • compatibility shims for old attribute names

__getattribute__ Runs Every Time

Python calls __getattribute__(self, name) for every attribute access, even when the attribute exists.

Example:

python
1class Logged:
2    def __init__(self):
3        self.value = 10
4
5    def __getattribute__(self, name):
6        print(f"Accessing {name}")
7        return super().__getattribute__(name)
8
9
10obj = Logged()
11print(obj.value)

This prints the log line even though value exists normally.

That is why __getattribute__ is useful for:

  • detailed access control
  • tracing and logging
  • proxy objects that intercept all reads
  • advanced attribute virtualization

But it also means mistakes are much more dangerous.

The Biggest Danger: Infinite Recursion

Inside __getattribute__, if you access self.some_attr directly, that triggers __getattribute__ again and can recurse forever.

Bad version:

python
class Broken:
    def __getattribute__(self, name):
        return self.__dict__[name]

This is unsafe because accessing self.__dict__ itself goes through __getattribute__.

Correct version:

python
1class Safe:
2    def __init__(self):
3        self.value = 42
4
5    def __getattribute__(self, name):
6        print(f"Reading {name}")
7        return super().__getattribute__(name)

The normal pattern is to delegate to super().__getattribute__(name) or object.__getattribute__(self, name).

How They Work Together

The lookup order is roughly:

  1. call __getattribute__
  2. if it finds the attribute, return it
  3. if it raises AttributeError, Python may then call __getattr__

That means __getattr__ is not a competitor to __getattribute__. It is a fallback after normal lookup fails.

Example using both:

python
1class Demo:
2    def __init__(self):
3        self.existing = "yes"
4
5    def __getattribute__(self, name):
6        return super().__getattribute__(name)
7
8    def __getattr__(self, name):
9        return f"missing:{name}"
10
11
12d = Demo()
13print(d.existing)
14print(d.unknown)

existing comes from normal lookup. unknown falls through to __getattr__.

When to Use Which One

Use __getattr__ when:

  • you only care about missing attributes
  • you want a safe default
  • you want less risk of breaking normal attribute access

Use __getattribute__ when:

  • you truly need to intercept every attribute access
  • you are building advanced framework behavior
  • you are comfortable handling recursion carefully

For most application code, __getattr__ is the better tool.

A Real-World Example: Proxy Objects

Proxy wrappers often use __getattr__ to delegate unknown attributes to another object.

python
1class Proxy:
2    def __init__(self, target):
3        self._target = target
4
5    def __getattr__(self, name):
6        return getattr(self._target, name)
7
8
9class User:
10    def __init__(self):
11        self.name = "Alice"
12
13
14proxy = Proxy(User())
15print(proxy.name)

This is a classic __getattr__ use case because it only needs to handle attributes the proxy does not define itself.

Common Pitfalls

One common mistake is using __getattribute__ when __getattr__ would have been enough. That adds complexity and increases the chance of recursion bugs.

Another mistake is forgetting to raise AttributeError in __getattr__ when an attribute truly does not exist. Python expects missing attributes to behave that way.

It is also easy to break introspection, debugging, and tooling if these methods return surprising values for standard attribute names.

Finally, overusing either method can make ordinary objects harder to reason about. Dynamic attribute tricks are useful, but they should be deliberate.

Summary

  • '__getattribute__ runs on every attribute access.'
  • '__getattr__ runs only when normal lookup fails.'
  • '__getattr__ is usually safer and better for fallback behavior.'
  • '__getattribute__ is more powerful but must delegate carefully to avoid infinite recursion.'
  • Use the simpler hook unless you truly need to intercept all attribute reads.

Course illustration
Course illustration

All Rights Reserved.