[go: up one dir, main page]

Python's getattr function PREMIUM

Trey Hunner smiling in a t-shirt against a yellow wall
Trey Hunner
4 min. read Python 3.10—3.14

Python's getattr function can dynamically lookup an attribute on any object by its name.

Let's talk about this slightly advanced Python built-in function.

Dynamically accessing an attribute in Python

Let's say we have an object and the name of an attribute on that object, represented as a string:

>>> from dataclasses import dataclass
>>> @dataclass
>>> class Point:
...     x: float
...     y: float
...     z: float
...
>>> point = Point(1, 2, 3)
>>> attribute = input("Enter x, y, or z: ")
Enter x, y, or z: x
>>> attribute
'x'

How can we access the x attribute on that point object, given that we don't know the attribute name we need as we're writing our code?

We can use Python's built-in getattr function for this:

>>> getattr(point, attribute)
1

The getattr function accepts an object and an attribute name and it returns the value of that attribute. If the attribute isn't defined, an exception will be raised:

>>> attribute = "a"
>>> getattr(point, attribute)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Point' object has no attribute 'a'

Though we can also supply an optional default value to return if that attribute doesn't exist:

>>> getattr(point, "a", 0)
0

That default value will only be used if the attribute doesn't exist:

>>> getattr(point, "x", 0)
1

Check whether an attribute exists

What if just want to check whether an object has a certain attribute?

For example, let's say we'd like to know whether an object has a __len__ method (implying that it would work with the built-in len function).

We could try to access that attribute and set a boolean to either True or False based on whether an AttributeError is raised:

def has_length(obj):
    """Return True if the object works with len()."""
    try:
        obj.__len__
    except AttributeError:
        return False
    return True

Or we could use the built-in hasattr function to specifically check whether the object has a __len__ attribute:

def has_length(obj):
    """Return True if the object works with len()."""
    return hasattr(obj, "__len__")

The hasattr function does access the attribute under the hood, but it only returns True or False based on whether an AttributeError exception was raised.

Why not access __dict__ directly?

If you're familiar with how Python stores its attributes, you might be wondering why getattr exists. Can't we directly access the __dict__ dictionary on our object instead?

>>> point.__dict__
{'x': 1, 'y': 2, 'z': 3}

We can! Directly accessing __dict__ dictionary works:

>>> attribute = "x"
>>> point.__dict__[attribute]
1

But it only works sometimes.

For example, here's a class with an area property:

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height

    @property
    def area(self):
        return self.width * self.height

Each instance of this class has an area attribute:

>>> rect = Rectangle(3, 4)
>>> rect.area
12

But that attribute doesn't exist in the object's __dict__ dictionary:

>>> rect.__dict__["area"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'area'

But the built-in getattr function will access that attribute as expected:

>>> getattr(rect, "area")
12

So __dict__ doesn't work for properties. It also doesn't work for classes that use __slots__ to store their attributes instead of __dict__.

Why not call the __getattribute__ method?

The built-in getattr function relies on an object's __getattribute__ method.

>>> rect.__getattribute__
<method-wrapper '__getattribute__' of Rectangle object at 0x76850e673cb0>

Instead of using getattr, can't we call the __getattribute__ method directly?

>>> rect.__getattribute__("area")
12

This does work, but we're not supposed to call this method directly.

Dunder methods are a contract between the implementer of an object and the Python interpreter. These methods are meant to be defined, but not called.

It's Python's job to call dunder methods, not ours.

So we should use the getattr function for the same reason we use the len function instead of calling the __len__ method and the str function instead of calling the __str__ method.

Don't use getattr if you can avoid it

If you ever see a hard-coded string being accessed with the getattr function, this is a sign that you probably don't need to use getattr:

>>> getattr(point, "x")
1

If you know the attribute you need to access at the time you write your code, just access that attribute!

>>> point.x
1

If there's a possibility that the attribute you're accessing might not exist you could use getattr with a default value, but that's a pretty unusual scenario in Python:

>>> getattr(point, "a", 0)
0

Usually we know whether each object we're working is expected to have certain attributes.

Use getattr for dynamic attribute lookups

The next time you need to dynamically look up an attribute based on a string that represents an attribute name, use Python's built-in getattr function:

some_value = getattr(some_object, some_attribute)

If you need to dynamically control the value of an attribute while it's being looked up on your class's instances, look into defining a __getattr__ method or a __getattribute__ method.

This is a free preview of a premium article. You have 2 previews remaining.