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 li开发者_如何学Cke 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).
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
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.
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)
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):
.
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)
Why not using pretty print, which already does all this?
http://docs.python.org/dev/library/pprint.html
精彩评论