pythondictionarydefaultdict

Looking for a way to accept or reject a dictionary trail w/o excepting


I want to do this:

    foo23 = base["foo23"]["subfoo"]["subsubfoo"]
    print(foo23)
    [2,3]

    foo23 = base["noexist"]["nothereeither"]["nope"]
    print(foo23)
    None

I can't seem to accomplish this, using defaultdict and specialized dictionaries. The failed access of the first call can return a 'None', but then the following fields cause an exception for it not being subscriptable. Just wondering if this is possible.


Solution

  • If you wanted to walk a tree by a list of keys where the tree might have nodes that where dictionaries or lists or values then you might do:

    def find_value_by_keys(root, list_of_keys):
        for key in list_of_keys:
            try:
                root = root[key]
            except KeyError:
                return None
        return root
    
    root = {
        "foo": {"bar": "baz"},
        "foo2": ["bar", "baz"]
    }
    print(find_value_by_keys(root, ["foo", "bar"]))
    print(find_value_by_keys(root, ["foo2", 1]))
    print(find_value_by_keys(root, ["foo", "noexist"]))
    print(find_value_by_keys(root, ["foo", 2]))
    

    That will give you:

    baz
    baz
    None
    None
    

    while failing fast and without resorting to a casting your tree to a default dict.

    If you wanted to support a list of keys that was a dot separated sting you might be able to do that if you guarded for only passing integer indexes to lists. Perhaps something like:

    def find_value_by_keys(root, list_of_keys):
        if isinstance(list_of_keys, str):
            list_of_keys = list_of_keys.split(".")
    
        for key in list_of_keys:
            try:
                root = root[int(key) if isinstance(root, list) else key]
            except (ValueError, KeyError):
                return None
        return root
    
    root = {
        "foo": {"bar": "baz"},
        "foo2": ["bar", "baz"]
    }
    print(find_value_by_keys(root, ["foo", "bar"]))
    print(find_value_by_keys(root, "foo.bar"))
    
    print(find_value_by_keys(root, ["foo2", 1]))
    print(find_value_by_keys(root, "foo2.1"))
    print(find_value_by_keys(root, "foo2.x"))
    
    print(find_value_by_keys(root, ["foo", "noexist"]))
    print(find_value_by_keys(root, "foo.noexist"))
    
    print(find_value_by_keys(root, ["foo", 2]))
    print(find_value_by_keys(root, "foo.2"))