Welcome, guest | Sign In | My Account | Store | Cart

Snippet of code that uses recursion to print nested dictionaries. It does not sort the entries!

Python, 24 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#! /usr/bin/python

def print_dict(dictionary, ident = '', braces=1):
    """ Recursively prints nested dictionaries."""

    for key, value in dictionary.iteritems():
        if isinstance(value, dict):
            print '%s%s%s%s' %(ident,braces*'[',key,braces*']') 
            print_dict(value, ident+'  ', braces+1)
        else:
            print ident+'%s = %s' %(key, value)

if __name__ == '__main__':

    example_dict = { 'key1' : 'value1',
                     'key2' : 'value2',
                     'key3' : { 'key3a': 'value3a' },
                     'key4' : { 'key4a': { 'key4aa': 'value4aa',
                                           'key4ab': 'value4ab',
                                           'key4ac': 'value4ac'},
                                'key4b': 'value4b'}
                   }

    print_dict(example_dict)

My first Recipe here.

I've been dealing with some configuration files that are loaded to python dictionaries. Needed a way to print them in a more readable way.

Since the configuration files can have nested sections, and those are loaded as nested dictionaries, I needed a way to print them with a indentation.

Since you don't know beforehand how deep those nesting goes, I had to think for a while and found out that some recursion would do the job.

I thing it came out pretty elegantly. What do you guys think?

Didn't need to sort, in my case, but it would be some nice feature, too.

1 comment

Scott S-Allen 9 years, 7 months ago  # | flag

Nice 'n simple, always good.

Your braces and 'indent' are tightly coupled as in the number of braces equals the number of indents. By swapping the two extra params for a 'depth' param, then use a couple extra methods like these helps tidy too:

tabs = lambda n: ' ' * n * 4 # or 2 or 8 or...
brace = lambda s, n: '%s%s%s' % ('['*n, s, ']'*n)

The other detail I note, constructively of course, is the focus upon dictionaries to the exclusion of other common, iterative, types. By swapping a couple of lines the recursion can branch better:

def recursive_print(src, dpth = 0, key = ''):
    """ Recursively prints nested elements."""
    tabs = lambda n: ' ' * n * 4 # or 2 or 8 or...
    brace = lambda s, n: '%s%s%s' % ('['*n, s, ']'*n)

    if isinstance(src, dict):
        for key, value in src.iteritems():
            print tabs(dpth) + brace(key, dpth)
            recursive_print(value, dpth + 1, key)
    elif isinstance(src, list):
        for litem in src:
            recursive_print(litem, dpth + 2)
    else:
        if key:
            print tabs(dpth) + '%s = %s' % (key, src)
        else:
            print tabs(dpth) + '- %s' % src

Not 100% work-alike, sorry, but illustrative.

The indent is, I believe, enough to show the hierarchy so the version for this task in my kit just uses single curly-braces, indeed it regenerates outlines as thinner dicts (sometimes useful, beyond browsing). I needed an object-introspecting tool, has a few more lines...

Also using "+" for string concatenation is okay for simplicity. I viewed the form vulgar, slower and cumbersome (SQL-gen code littered with 'em is particularly offending). Like most things, once you analyze & test, there can be valid uses.

Simple joins:

s = s + t

For little stuff is actually more than twice as fast as:

's%s%' % (s, t)

... for short strings. I find it makes code clearer in some instances. By the time more elements & dicts are involved, formatting easily wins on 'clarity'.

brace = lambda s, n: '%s%s%s' % ('['*n, s, ']'*n)

... is totally fine by me, but below is a smidgen tidier

brace = lambda s, n: '['*n + s + ']'*n

Then, of course, add a notch 'r two and it stuffs elegant simplicity into nested obscurity.

rindnt = lambda s, n, c=' ': s.rjust(n, c)
brace = lambda s, n, l, r: l*n + s + r*n

rindnt(brace('8-8', 2, '*-{', '}-*'), 20, '.')

So, that's my 0.02 regarding tips towards improved usable-elegance, but new ones often appear. Good source is always a good source! ;-)