在Python中使用pprint.pprint之后,是否可以避免排序字典输出?

时间:2018-08-10 14:11:28

标签: python dictionary pretty-print pprint

代码是:

from pprint import pprint
d = {"b" : "Maria", "c" : "Helen", "a" : "George"}
pprint(d, width = 1)

输出为:

{'a': 'George',
'b': 'Maria',
'c': 'Helen'}

但是,所需的输出是:

{'b': 'Maria',
'c': 'Helen',
'a': 'George'}

这可以用pprint完成吗,还是有另一种方法?

4 个答案:

答案 0 :(得分:3)

如果您阅读pprint.py的来源,则会在PrettyPrinter._pprint_dict()中找到负责格式化字典的方法:

def _pprint_dict(self, object, stream, indent, allowance, context, level):
    write = stream.write
    write('{')
    if self._indent_per_level > 1:
        write((self._indent_per_level - 1) * ' ')
    length = len(object)
    if length:
        items = sorted(object.items(), key=_safe_tuple)
        self._format_dict_items(items, stream, indent, allowance + 1,
                                context, level)
    write('}')

_dispatch[dict.__repr__] = _pprint_dict

这里有items = sorted(object.items(), key=_safe_tuple)行,因此字典项在进行格式化之前总是先排好序,您必须自己复制,粘贴并在自己的脚本中删除有问题的行来覆盖它:

import pprint as pp
def _pprint_dict(self, object, stream, indent, allowance, context, level):
    write = stream.write
    write('{')
    if self._indent_per_level > 1:
        write((self._indent_per_level - 1) * ' ')
    length = len(object)
    if length:
        self._format_dict_items(object.items(), stream, indent, allowance + 1,
                                context, level)
    write('}')
pp.PrettyPrinter._dispatch[dict.__repr__] = _pprint_dict

这样:

pp.pprint({"b" : "Maria", "c" : "Helen", "a" : "George"}, width=1)

将输出(在Python 3.6+中):

{'b': 'Maria',
 'c': 'Helen',
 'a': 'George'}

答案 1 :(得分:2)

对于Python 3.7 +,dict保留插入顺序。对于任何以前的版本,您将需要使用OrderedDict来使密钥保持顺序。

尽管,从doc on pprint

  

在对显示进行计算之前,字典按键进行排序。

这意味着pprint将会中断您想要的订单。

使用json.dumps

虽然可以将pprint.PrettyPrinter子类化,而不在显示之前对键进行排序,但这很繁琐,而且一种很好的选择是使用json.dumps来漂亮地打印数据。

代码

import json
from collections import OrderedDict

# For Python 3.6 and prior, use an OrderedDict
d = OrderedDict(b="Maria", c="Helen", a="George")

print(json.dumps(d, indent=1))

输出

{
 "b": "Maria",
 "c": "Helen",
 "a": "George"
}

答案 2 :(得分:1)

您应该使用python集合库中的OrderedDict来保持顺序不变

from collections import OrderedDict
from pprint import pprint
d = OrderedDict({"b" : "Maria", "c" : "Helen", "a" : "George"})
pprint(d, width = 1)

更新:

由于输出很重要,因此可以使用以下代码,这是一个技巧,但是您可以创建一个函数来实现此功能:

from collections import OrderedDict
d = OrderedDict({"b" : "Maria", "c" : "Helen", "a" : "George"})
print('{', end='')
total_len = len(d)
current_index = 1
for key, value in d.items():
    print('\''+key+'\': \'' + value+ '\'', end='')
    if current_index<total_len:
        print(',')
    else:
        print('}')
    current_index += 1

答案 3 :(得分:1)

一个更通用的解决方案是使用unittest.mock.patch来覆盖内置的sorted函数,该函数除了返回给定的第一个参数外什么都不做:

import pprint
from unittest.mock import patch

def unsorted_pprint(*args, **kwargs):
    with patch('builtins.sorted', new=lambda l, **_: l):
        orig_pprint(*args, **kwargs)

orig_pprint = pprint.pprint
pprint.pprint = unsorted_pprint

这样:

pprint.pprint({"b" : "Maria", "c" : "Helen", "a" : "George"})

输出:

{'b': 'Maria', 'c': 'Helen', 'a': 'George'}