Get nested attribute from a python object
Asked Answered
I

5

15

I have an object with nested attributes like so:

obj:
    attr_1:
        attr_2

When both attr_1 and attr_2 exists, I can get it like so:

obj.attr_1.attr_2

But what if I'm not sure if either attribute exists? In this case, construction of getattr(obj, 'attr_1.attr_2', None) does not work.

What are the best practices to replace this construction?

Divide that into two getattr statements?

Inbred answered 5/3, 2017 at 8:34 Comment(1)
Possible duplicate of getattr and setattr on nested objects?Ard
W
19

You can use operator.attrgetter() in order to get multiple attributes at once:

from operator import attrgetter

my_attrs = attrgetter(attr1, attr2)(obj)
Wingate answered 5/3, 2017 at 8:36 Comment(4)
I think OP wants my_attrs = ('attr1.attr2')(obj)Bromley
The title says something different though.Reconsider
@Reconsider yes, the title makes this ambiguous.Bromley
Sorry. I want to get obj.attr1.attr2 using getattr or another method.Inbred
E
4

As stated in this answer, the most straightforward solution would be to use operator.attrgetter (more info in this python docs page).

If for some reason, this solution doesn't make you happy, you could use this code snippet:

def multi_getattr(obj, attr, default = None):
"""
Get a named attribute from an object; multi_getattr(x, 'a.b.c.d') is
equivalent to x.a.b.c.d. When a default argument is given, it is
returned when any attribute in the chain doesn't exist; without
it, an exception is raised when a missing attribute is encountered.

"""
attributes = attr.split(".")
for i in attributes:
    try:
        obj = getattr(obj, i)
    except AttributeError:
        if default:
            return default
        else:
            raise
return obj

# Example usage
obj  = [1,2,3]
attr = "append.__doc__.capitalize.__doc__"

multi_getattr(obj, attr) #Will return the docstring for the
                         #capitalize method of the builtin string
                         #object

from this page, which does work. I tested and used it.

Eyesore answered 21/9, 2018 at 14:39 Comment(0)
R
2

I would suggest using python's built-in operator.attrgetter:

from operator import attrgetter
attrgetter('attr0.attr1.attr2.attr3')(obj)
Rodman answered 21/6, 2022 at 9:4 Comment(0)
A
0

If you have the attribute names you want to get in a list, you can do the following:

my_attrs = [getattr(obj, attr) for attr in attr_list]
Attorney answered 15/7, 2021 at 20:0 Comment(0)
M
0

A simple, but not very eloquent way, to get multiple attr would be to use tuples with or without brackets something like

aval, bval =  getattr(myObj,"a"), getattr(myObj,"b")

but I think you might be wanting instead to get atrribute of a contained object with the way you are using dot notation. In which case it would be something like

getattr(myObj.contained, "c")

where contained is an object cotained within myObj object and c is an attribute of contained. Let me know if this is not what you want.

Meal answered 15/7, 2021 at 20:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.