Tutorial :Python dictionary formatting



Question:

I made a Python function to convert dictionaries to formatted strings. My goal was to have a function take a dictionary for input and turn it into a string that looked good. For example, something like {'text':'Hello', 'blah':{'hi':'hello','hello':'hi'}} would be turned into this:

  text:      Hello  blah:      hi:          hello      hello:          hi  

This is the code I wrote:

indent = 0    def format_dict(d):      global indent      res = ""      for key in d:          res += ("   " * indent) + key + ":\n"          if not type(d[key]) == type({}):              res += ("   " * (indent + 1)) + d[key] + "\n"          else:              indent += 1              res += format_dict(d[key])              indent -= 1      return res  #test  print format_dict({'key with text content':'some text',                     'key with dict content':                    {'cheese': 'text', 'item':{'Blah': 'Hello'}}})  

It works like a charm. It checks if the dictionary's item is another dictionary, in which case it process that, or something else, then it would use that as the value. The problem is: I can't have a dictionary and a string together in a dictionary item. For example, if I wanted:

  blah:      hi      hello:          hello again  

there'd be no way to do it. Is there some way I could have something like a list item in a dictionary. Something like this {'blah':{'hi', 'hello':'hello again'}}? And if you provide a solution could you tell me how I would need to change my code (if it did require changes).
Note: I am using python 2.5


Solution:1

You can simply store a list in the dictionary. Also, it's better not to use a global to store the indentation. Something along the lines of:

def format_value(v, indent):      if isinstance(v, list):           return ''.join([format_value(item, indent) for item in v])      elif isinstance(v, dict):           return format_dict(v, indent)      elif isinstance(v, str):           return ("   " * indent) + v + "\n"    def format_dict(d, indent=0):      res = ""      for key in d:          res += ("   " * indent) + key + ":\n"          res += format_value(d[key], indent + 1)      return res  


Solution:2

You can express dictionaries as having lists of children:

{'blah': [      'hi',      {'hello':[          'hello again'      ]},      {'goodbye':[          'hasta la vista, baby'      ]}  ]}  

A consequence of this is that each dictionary will have just a single key-value pair. On the plus side, it means you can have repeating keys and deterministic ordering, just like XML.

EDIT: On second thought, you could simply fold 'hello' and 'goodbye' into a single dictionary, though I would personally find that to be quite confusing, since you could now have a mish-mash of ordered and unordered stuff. So I guess the one-key-per-dictionary rule is more of a recommendation than a requirement.


Solution:3

Why not just use yaml?

import yaml  import StringIO    d = {'key with text content':'some text',        'key with dict content':       {'cheese': 'text', 'item': {'Blah': 'Hello'}}}  s = StringIO.StringIO()  yaml.dump(d, s)  print s.getvalue()  

this prints out:

key with dict content:    cheese: text    item: {Blah: Hello}  key with text content: some text  

and you can load it back in to a dict

s.seek(0)  d = yaml.load(s)  


Solution:4

A dictionary is a mapping, so you can't have a key without a value. However, the closest to that would be for a key to have the value of None. Then add a check for None before the if not type(d[key]) == type({}): line and continue to avoid printing the value. BTW, that line would be better as if not isinstance(d[key], dict):.


Solution:5

As mentioned, you'll need to use lists as values whenever you want to have a text and dictionary at the same level. here's some code that prints what you need.

# -*- coding: utf-8 -*-  #!/usr/bin/env python2.5  # http://stackoverflow.com/questions/2748378/python-dictionary-formating    def pretty_dict(d, indent=0, spacer='.'):      """      takes a dict {'text':'Hello', 'blah':{'hi':'hello','hello':'hi'}}      And prints:        text:          Hello      blah:          hi:              hello          hello:              hi        """      kindent = spacer * indent        if isinstance(d, basestring):          return kindent + d        if isinstance(d, list):          return '\n'.join([(pretty_dict(v, indent, spacer)) for v in d])        return '\n'.join(['%s%s:\n%s' % (kindent, k, pretty_dict(v, indent + 1, spacer))           for k, v in d.items()])      test_a = {'text':'Hello', 'blah':{'hi':'hello','hello':'hi'}}  test_b = {'key with text content':'some text', 'key with dict content':      {'cheese': 'text', 'item':{'Blah': 'Hello'}}}  test_c = {'blah':['hi', {'hello':'hello again'}]}  test_d = {'blah': [      'hi',      {'hello':[          'hello again'      ]},      {'goodbye':[          'hasta la vista, baby'  ]}  ]}      if __name__ == '__main__':      print pretty_dict(test_a)      print pretty_dict(test_b)      print pretty_dict(test_c)      print pretty_dict(test_d)  


Solution:6

Why not using pretty print, which already does all this?

http://docs.python.org/dev/library/pprint.html


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »