Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convenient way to handle deeply nested dictionary in Python

I have a deeply nested dictionary in python thats taking up a lot of room. Is there a way to abbreviate something like this

master_dictionary['sub_categories'][sub_cat_name]['attributes'][attribute_name]['special_type']['nested_children'][child_cat_name][color] = blue

to this for example

nested_child_info[color] = blue

And still have it edit the dictionary ? I hope that makes sense.

like image 342
TJB Avatar asked Apr 24 '18 21:04

TJB


People also ask

How does Python handle nested dictionary?

One way to add a dictionary in the Nested dictionary is to add values one be one, Nested_dict[dict][key] = 'value'. Another way is to add the whole dictionary in one go, Nested_dict[dict] = { 'key': 'value'}.

Can Python dictionaries be nested to any depth?

Dictionaries can be nested to any depth. All the keys in a dictionary must be of the same type. Items are accessed by their position in a dictionary. Dictionaries are mutable.

How do I store a large dictionary in Python?

If you just want to work with a larger dictionary than memory can hold, the shelve module is a good quick-and-dirty solution. It acts like an in-memory dict, but stores itself on disk rather than in memory. shelve is based on cPickle, so be sure to set your protocol to anything other than 0.

How do you iterate over a nested dictionary in Python?

just write d. items() , it will work, by default on iterating the name of dict returns only the keys.


1 Answers

Similar to @fferri. You will always have to specify the items in a long list. Get a reference to the final dict using reduce and getitem:

from functools import reduce
from operator import getitem

d = {1:{2:{3:{4:5}}}}

foo = 2
items = [1,foo,3]
result = d
info = reduce(getitem, items, d)


>>> info[4]
5
>>> d
{1: {2: {3: {4: 5}}}}
>>> info[4] = 99
>>> d
{1: {2: {3: {4: 99}}}}

I was also playing around with a class but it doesn't seem to have many advantages - except you could customize a key error exception so that the error message would tell you which key at which depth is missing.

class Drilldown:
    def __init__(self, d, path):
        #self.final = reduce(getitem, path, d)
        self.final = d
        for i, item in enumerate(path, 1):
            try:
                self.final = self.final[item]
            except KeyError as e:
                msg = ''.join('[{}]' for _ in range(i))
                msg = msg.format(*path[:i])
                msg = 'The last key in the path "{}" does not exist'.format(msg)
                e.args = [msg]
                raise
    def __call__(self, item):
        return self.final[item]
    def __setitem__(self, item, value):
        self.final[item] = value
    def __getitem__(self, item):
        return self.final[item]
    def __str__(self):
        return str(self.final)
    def __repr__(self):
        return repr(self.final)

>>> z = 19
>>> items = [1,2,z]
>>> q = Drilldown(d,items)
Traceback (most recent call last):
  File "<pyshell#68>", line 1, in <module>
    q = Drilldown(d,items)
  File "C:\pyProjects33\tmp.py", line 32, in __init__
    self.final = self.final[item]
KeyError: 'The last key in the path "[1][2][19]" does not exist'

>>> 
>>> #normal usage
>>> items = [1,2,3]
>>> q = Drilldown(d,items)
>>> d
{1: {2: {3: {4: 5}}}}
>>> q
{4: 5}
>>> q(4)
5
>>> q[4]
5
>>> q[4] += 20
>>> q
{4: 25}
>>> d
{1: {2: {3: {4: 25}}}}
>>> q['foo'] = '99'
>>> q
{4: 25, 'foo': '99'}
>>> d
{1: {2: {3: {4: 25, 'foo': '99'}}}}
>>> 
like image 143
wwii Avatar answered Sep 25 '22 14:09

wwii