任何方式来适当漂亮打印有序的字典?

我喜欢Python中的pprint模块。 我用它进行testing和debugging。 我经常使用宽度选项来确保输出很好地适合我的terminal窗口。

它工作得很好,直到他们在Python 2.7中添加了新的有序字典types (我真的很喜欢另一个很酷的function)。 如果我试图漂亮地打印一个有序的字典,它不会很好地显示。 整个事物不是每个键值对都在一条线上,而是显示在一条很长的线上,这个线很多,很难读。

这里有没有人有办法让它打印得很好,就像旧的无序字典一样? 如果我花了足够的时间,我可能会想出一些东西,可能使用PrettyPrinter.format方法,但我想知道是否有人在这里已经知道一个解决scheme。

更新:我为此提交了一个错误报告。 你可以在http://bugs.python.org/issue10592看到它。

作为临时解决方法,您可以尝试以JSON格式进行转储。 你失去了一些types的信息,但它看起来不错,并保持秩序。

import json pprint(data, indent=4) # ^ugly print(json.dumps(data, indent=4)) # ^nice 

如果你的OrderedDict的顺序是一个alphatypes,下面的工作将会起作用,因为pprint会在打印之前对字典进行sorting。

 pprint(dict(o.items())) 

这里的另一个解决scheme是通过在内部覆盖和使用库存pprint()函数。 与我之前的不同,它处理OrderedDict在另一个容器(如list ,也应该能够处理给定的任何可选的关键字参数 – 但是它没有对另一个提供的输出进行相同程度的控制。

它通过将库存函数的输出redirect到一个临时缓冲区进行操作,然后在将其发送到输出stream之前将其包装。 虽然最终的产出并不是特别漂亮,但它是体面的,可能是“足够好”作为解决方法。

更新2.0

通过使用标准库textwrap模块进行简化,并修改为可在Python 2和Python 3中使用。

 from collections import OrderedDict try: from cStringIO import StringIO except ImportError: # Python 3 from io import StringIO from pprint import pprint as pp_pprint import sys import textwrap def pprint(object, **kwrds): try: width = kwrds['width'] except KeyError: # unlimited, use stock function pp_pprint(object, **kwrds) return buffer = StringIO() stream = kwrds.get('stream', sys.stdout) kwrds.update({'stream': buffer}) pp_pprint(object, **kwrds) words = buffer.getvalue().split() buffer.close() # word wrap output onto multiple lines <= width characters try: print >> stream, textwrap.fill(' '.join(words), width=width) except TypeError: # Python 3 print(textwrap.fill(' '.join(words), width=width), file=stream) d = dict((('john',1), ('paul',2), ('mary',3))) od = OrderedDict((('john',1), ('paul',2), ('mary',3))) lod = [OrderedDict((('john',1), ('paul',2), ('mary',3))), OrderedDict((('moe',1), ('curly',2), ('larry',3))), OrderedDict((('weapons',1), ('mass',2), ('destruction',3)))] 

示例输出:

 pprint(d, width=40) 

» {'john': 1, 'mary': 3, 'paul': 2}

 pprint(od, width=40) 

» OrderedDict([('john', 1), ('paul', 2),
('mary', 3)])

 pprint(lod, width=40) 

» [OrderedDict([('john', 1), ('paul', 2),
('mary', 3)]), OrderedDict([('moe', 1),
('curly', 2), ('larry', 3)]),
OrderedDict([('weapons', 1), ('mass',
2), ('destruction', 3)])]

打印一个有序的字典,例如

 from collections import OrderedDict d=OrderedDict([ ('a', OrderedDict([ ('a1',1), ('a2','sss') ])), ('b', OrderedDict([ ('b1', OrderedDict([ ('bb1',1), ('bb2',4.5)])), ('b2',4.5) ])), ]) 

我做

 def dict_or_OrdDict_to_formatted_str(OD, mode='dict', s="", indent=' '*4, level=0): def is_number(s): try: float(s) return True except ValueError: return False def fstr(s): return s if is_number(s) else '"%s"'%s if mode != 'dict': kv_tpl = '("%s", %s)' ST = 'OrderedDict([\n'; END = '])' else: kv_tpl = '"%s": %s' ST = '{\n'; END = '}' for i,k in enumerate(OD.keys()): if type(OD[k]) in [dict, OrderedDict]: level += 1 s += (level-1)*indent+kv_tpl%(k,ST+dict_or_OrdDict_to_formatted_str(OD[k], mode=mode, indent=indent, level=level)+(level-1)*indent+END) level -= 1 else: s += level*indent+kv_tpl%(k,fstr(OD[k])) if i!=len(OD)-1: s += "," s += "\n" return s print dict_or_OrdDict_to_formatted_str(d) 

收益率

 "a": { "a1": 1, "a2": "sss" }, "b": { "b1": { "bb1": 1, "bb2": 4.5 }, "b2": 4.5 } 

要么

 print dict_or_OrdDict_to_formatted_str(d, mode='OD') 

这产生了

 ("a", OrderedDict([ ("a1", 1), ("a2", "sss") ])), ("b", OrderedDict([ ("b1", OrderedDict([ ("bb1", 1), ("bb2", 4.5) ])), ("b2", 4.5) ])) 

这是一个黑客执行pprint 。 在打印之前, pprint键进行sorting,所以为了保持顺序,我们只需要按照我们想要的方式进行键sorting。

请注意,这会影响items()函数。 所以你可能想要保留和恢复执行pprint后重写的函数。

 from collections import OrderedDict import pprint class ItemKey(object): def __init__(self, name, position): self.name = name self.position = position def __cmp__(self, b): assert isinstance(b, ItemKey) return cmp(self.position, b.position) def __repr__(self): return repr(self.name) OrderedDict.items = lambda self: [ (ItemKey(name, i), value) for i, (name, value) in enumerate(self.iteritems())] OrderedDict.__repr__ = dict.__repr__ a = OrderedDict() a[4] = '4' a[1] = '1' a[2] = '2' print pprint.pformat(a) # {4: '4', 1: '1', 2: '2'} 

这非常粗糙,但我只需要一种可视化由任意映射和Iterables组成的数据结构的方法,这就是我在放弃之前所提出的。 它是recursion的,所以它将通过嵌套结构和列表下降很好。 我使用集合中的Mapping和Iterable抽象基类来处理任何事情。

我瞄准几乎yaml像输出简洁的Python代码,但没有完全做到这一点。

 def format_structure(d, level=0): x = "" if isinstance(d, Mapping): lenk = max(map(lambda x: len(str(x)), d.keys())) for k, v in d.items(): key_text = "\n" + " "*level + " "*(lenk - len(str(k))) + str(k) x += key_text + ": " + format_structure(v, level=level+lenk) elif isinstance(d, Iterable) and not isinstance(d, basestring): for e in d: x += "\n" + " "*level + "- " + format_structure(e, level=level+4) else: x = str(d) return x 

和一些testing数据使用OrderedDict和OrderedDicts列表…(Sheesh Python需要OrderedDict文字很糟糕…)

 d = OrderedDict([("main", OrderedDict([("window", OrderedDict([("size", [500, 500]), ("position", [100, 900])])), ("splash_enabled", True), ("theme", "Dark")])), ("updates", OrderedDict([("automatic", True), ("servers", [OrderedDict([("url", "http://server1.com"), ("name", "Stable")]), OrderedDict([("url", "http://server2.com"), ("name", "Beta")]), OrderedDict([("url", "http://server3.com"), ("name", "Dev")])]), ("prompt_restart", True)])), ("logging", OrderedDict([("enabled", True), ("rotate", True)]))]) print format_structure(d) 

产生以下输出:

  main: window: size: - 500 - 500 position: - 100 - 900 splash_enabled: True theme: Dark updates: automatic: True servers: - url: http://server1.com name: Stable - url: http://server2.com name: Beta - url: http://server3.com name: Dev prompt_restart: True logging: enabled: True rotate: True 

我在使用str.format()更好的alignment方式方面有一些想法,但是不想深入研究它。 你需要dynamic指定字段的宽度取决于你想要的alignmenttypes,这会变得棘手或麻烦。

无论如何,这显示我的数据在可读的层次结构,所以适用于我!

 def pprint_od(od): print "{" for key in od: print "%s:%s,\n" % (key, od[key]) # Fixed syntax print "}" 

你去了^^

 for item in li: pprint_od(item) 

要么

 (pprint_od(item) for item in li) 

pprint()方法只是调用其中的__repr__()方法,而OrderedDict在其方法中似乎没有做太多的工作(或者没有其他方法)。

这是一个便宜的解决scheme, 如果你不关心订单在PPRINT OUTPUT中可见的情况 ,这可能是一个很大的,如果:

 class PrintableOrderedDict(OrderedDict): def __repr__(self): return dict.__repr__(self) 

我真的很惊讶,订单没有保存好啊。

您可以重新定义pprint()并拦截OrderedDict的调用。 这是一个简单的例子。 正如所写的, OrderedDict重写代码忽略了可能已经传递的任何可选的streamindentwidthdepth关键字,但是可以通过增强来实现它们。 不幸的是,这种技术不会在另一个容器内处理它们,比如OrderDictlist

 from collections import OrderedDict from pprint import pprint as pp_pprint def pprint(obj, *args, **kwrds): if not isinstance(obj, OrderedDict): # use stock function return pp_pprint(obj, *args, **kwrds) else: # very simple sample custom implementation... print "{" for key in obj: print " %r:%r" % (key, obj[key]) print "}" l = [10, 2, 4] d = dict((('john',1), ('paul',2), ('mary',3))) od = OrderedDict((('john',1), ('paul',2), ('mary',3))) pprint(l, width=4) # [10, # 2, # 4] pprint(d) # {'john': 1, 'mary': 3, 'paul': 2} pprint(od) # { # 'john':1 # 'paul':2 # 'mary':3 # } 

如果字典项目都是一种types,你可以使用惊人的数据处理库pandas

 >>> import pandas as pd >>> x = {'foo':1, 'bar':2} >>> pd.Series(x) bar 2 foo 1 dtype: int64 

要么

 >>> import pandas as pd >>> x = {'foo':'bar', 'baz':'bam'} >>> pd.Series(x) baz bam foo bar dtype: object 

你也可以使用这个简化的kzh答案:

 pprint(data.items(), indent=4) 

它保留的顺序,并将输出几乎相同webwurst答案( 打印通过JSON转储 )。