Python dictionary formatting

4
我写了一个Python函数来将字典转换为格式化字符串。我的目标是让函数接收一个字典作为输入,并将其转换为好看的字符串。例如,像{'text':'Hello', 'blah':{'hi':'hello','hello':'hi'}}这样的东西会被转换成这样:
text:
    Hello
blah:
    hi:
        hello
    hello:
        hi
这是我写的代码:
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'}}})

它非常好用。它检查字典项是否是另一个字典,如果是,则处理该字典,否则将其用作值。问题是:我不能在字典项中同时放置字典和字符串。例如,如果我想要:
blah:
    hi
    hello:
        hello again
就没有办法做到。有没有办法在字典中拥有类似列表项的东西。像这样{'blah':{'hi', 'hello':'hello again'}} ?如果您提供解决方案,能否告诉我需要如何更改我的代码(如果确实需要更改)。 注意:我正在使用python 2.5。

4
有一个模块叫做pprint可以帮助你避免重新发明轮子,或者至少避免重新发明轮子的部分:http://docs.python.org/dev/library/pprint.html - msw
这听起来像是YAML - endolith
我也写了一个函数来完成这个任务: https://dev59.com/XXA75IYBdhLWcg3wkJ31#22649051 - Al Conrad
6个回答

2
您可以将字典表示为具有子列表的形式:

您可以将字典表示为具有子列表的形式:

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

这会导致每个字典只有一个键值对。好处是,您可以有重复的键和确定性排序,就像XML一样。
编辑:仔细想想,您可以将“hello”和“goodbye”折叠成单个字典,但我个人认为这会相当令人困惑,因为现在您可能会有有序和无序混杂的东西。因此,我想一个字典一个键的规则更像是建议而不是要求。

2

您可以在字典中简单地存储列表。此外,最好不要使用全局变量来存储缩进。可以采用以下方式:

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

我该如何使用这个函数? - None
使用您的示例,您可以将字典定义为d = {'blah':['hi', {'hello':'hello again'}]}。换句话说,值可以是字典、列表或字符串。然后调用format_dict(d)。 - Ray

2
为什么不直接使用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()

这是英语文本,翻译成中文为:"这将打印出:"。
key with dict content:
  cheese: text
  item: {Blah: Hello}
key with text content: some text

你可以将它重新加载到字典中。
s.seek(0)
d = yaml.load(s)

首先,我没有安装yaml(也不知道是否可以安装)。其次,这就是我想要的,因为如果你的例子是正确的,第二层字典也不会被处理,而只会显示为“item: {Blah: Hello}”。 - None
好的,我想问一下以防万一。 - Toni Ruža

0
如上所述,每当您想要在同一级别上拥有文本和字典时,您需要使用列表作为值。以下是一些代码,可以打印出您所需的内容。
# -*- coding: utf-8 -*-
#!/usr/bin/env python2.5
# https://dev59.com/503Sa4cB1Zd3GeqPv4Z2

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)

0
一个字典是一种映射,所以你不能有一个没有值的键。然而,最接近这个的是让一个键的值为None。然后在if not type(d[key]) == type({}):这行代码之前添加一个检查None的语句,并使用continue来避免打印该值。顺便说一下,那行代码最好写成if not isinstance(d[key], dict):

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接