Skip to content Skip to sidebar Skip to footer

Accessing Python Dict Using Nested Key Lookup String

I am looking to create a simple nested 'lookup' mechanism in python, and wanted to make sure there wasn't already something somewhere hidden in the vast libraries in python that do

Solution 1:

There's nothing in the standard library for this purpose, but it is rather easy to code this yourself:

>>> key = "root.secondary.user2">>> reduce(dict.get, key.split("."), my_dict)
{'age': 25, 'name': 'fred'}

This exploits the fact that the look-up for the key k in the dictionary d can be written as dict.get(d, k). Applying this iteratively using reduce() leads to the desired result.

Edit: For completeness three functions to get, set or delete dictionary keys using this method:

defget_key(my_dict, key):
    return reduce(dict.get, key.split("."), my_dict)

defset_key(my_dict, key, value):
    key = key.split(".")
    my_dict = reduce(dict.get, key[:-1], my_dict)
    my_dict[key[-1]] = value

defdel_key(my_dict, key):
    key = key.split(".")
    my_dict = reduce(dict.get, key[:-1], my_dict)
    del my_dict[key[-1]]

Solution 2:

You can have that. You can subclass dict, add the key lookup (and even retain the name dict) by using code similar to the one below. The {...} form however will still use the builtin dict class (now called orig_dict), so you have to enclose it, like so: Dict({...}). This implementation recursively converts dictionaries to the new form, so you don't have to use the method above for any dictionary entries that are plain dictionaries themselves.

orig_dict = dictclassDict(orig_dict):
    def__init__(self, *args, **kwargs):
        super(Dict, self).__init__(*args, **kwargs)
        for k, v in self.iteritems():
            iftype(v) == orig_dict andnotisinstance(v, Dict):
                super(Dict, self).__setitem__(k, Dict(v))
    def__getattribute__(self, k):
        try: returnsuper(Dict, self).__getattribute__(k)
        except: return self.__getitem__(k)
    def__setattr__(self, k, v):
        if self.has_key(k): self.__setitem__(k, v)
        else: returnsuper(Dict, self).__setattr__(k, v)
    def__delattr__(self, k):
        try: self.__delitem__(k)
        except: super(Dict, self).__delattr__(k)
    def__setitem__(self, k, v):
        toconvert = type(v) == orig_dict andnotisinstance(v, Dict)
        super(Dict, self).__setitem__(k, Dict(v) if toconvert else v)

# dict = Dict  <-- you can even do this but I advise against it# testing:
b = Dict(a=1, b=Dict(c=2, d=3))
c = Dict({'a': 1, 'b': {'c': 2, 'd': 3}})
d = Dict(a=1, b={'c': 2, 'd': {'e': 3, 'f': {'g': 4}}})

b.a = b.b
b.b = 1
d.b.d.f.g = 40del d.b.d.e
d.b.c += d.b.d.f.g
c.b.c += c.a
del c.a
print b
print c
print d

Solution 3:

Recursion still works.

def walk_into( dict, key ):
    head, _, tail = key.partition('.')
    iftail:
        return walk_into( dict[head], tail )
    return dict, key
d, k = walk_into( my_dict, "root.secondary.user2" )

d[k] can be used for getting or putting a new value.

Solution 4:

I have a pretty complete implementation for this and some other stuff here. Repository here, trict.util combined with the __get__ method in trict.trict might have the stuff you need if you don't feel like installing it. Also it actually is in conda-forge even though the README might say otherwise if I haven't gotten around to updating it before you're reading this.

Post a Comment for "Accessing Python Dict Using Nested Key Lookup String"