任何方式来适当漂亮打印有序的字典?
我喜欢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
重写代码忽略了可能已经传递的任何可选的stream
, indent
, width
或depth
关键字,但是可以通过增强来实现它们。 不幸的是,这种技术不会在另一个容器内处理它们,比如OrderDict
的list
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转储 )。