Search code examples
pythongetattr

Is there a library to follow a sequence of indexing and `getattr` operations?


I have a bunch of objects, they have members, their members have members, ..., somewhere I need to do indexing, and then access members ...

So, basically, I want to get obj.member1.member2[3].member4 and I also want to assign obj.member1[2].member3.member4 = new_value. I want to generate these "paths" which describe when to use getattr and when to use indexing dynamically. Is there a library for this? I imagine interface like

get_obj_path(obj, (("member1", "a"), ("member2", "a"), (3, "i"), ("member4", "a")))

and

assign_obj_path(obj, (("member1", "a"), (2, "i"), ("member3", "a"), ("member4", "a")), new_value)

Solution

  • You can implement those functions yourself:

    def get_obj_path(obj, path):
        if not path:
            return obj
        (key, kind), *path = path
        if kind == "a":
            obj = getattr(obj, key)
        elif kind == "i":
            obj = obj[key]
        else:
            raise ValueError(f"invalid kind '{kind}'.")
        return get_obj_path(obj, path)
    
    def assign_obj_path(obj, path, value):
        (key, kind), *path = path
        if not path:
            if kind == "a":
                setattr(obj, key, value)
            elif kind == "i":
                obj[key] = value
            else:
                raise ValueError(f"invalid kind '{kind}'.")
        else:
            if kind == "a":
                obj = getattr(obj, key)
            elif kind == "i":
                obj = obj[key]
            else:
                raise ValueError(f"invalid kind '{kind}'.")
            assign_obj_path(obj, path, value)
    
    # Test
    class MyClass: pass
    obj1 = MyClass()
    obj1.i = 1
    obj2 = MyClass()
    obj2.lst = [obj1]
    assign_obj_path(obj2, (("lst", "a"), (0, "i"), ("i", "a")), 2)
    print(get_obj_path(obj2, (("lst", "a"), (0, "i"), ("i", "a"))))
    # 2