pprint 排序字典但不是集合?

2022-01-17 00:00:00 python python-3.x dictionary set pprint

问题描述

我知道 dicts 和 sets 没有顺序,所以相等的 sets 或 dicts 可能会打印不同的内容(所有测试都使用 Python 3.6.1):

>>>对于 {0, 8}, {8, 0}, {0:0, 8:8}, {8:8, 0:0} 中的 obj:打印(对象){0, 8}{8, 0}{0:0, 8:8}{8:8, 0:0}

我刚刚意识到 pprint (pretty-print") 对 dicts 进行排序,但不对集合进行排序:

>>>对于 {0, 8}, {8, 0}, {0:0, 8:8}, {8:8, 0:0} 中的 obj:pprint.pprint(obj){0, 8}{8, 0}{0:0, 8:8}{0:0, 8:8}

它的文档还说字典在计算显示之前按键排序".但是为什么它也不排序集合呢?在我看来并不漂亮.有没有办法制作排序集?也在嵌套结构中,因为这是 pprint 的主要目的.

解决方案

这是在 问题中提出的27495,这是一个错误,而不仅仅是一个设计选择,但显然还没有解决.

以下是问题中的另一个示例,它可能更清楚地说明了您在 Python 3 中识别的行为:

<块引用>

>>>导入字符串,pprint>>>pprint.pprint(set(string.digits)){'7'、'1'、'9'、'8'、'3'、'0'、'2'、'5'、'6'、'4'}

同样适用于 frozenset(),但请注意多行 pprint 输出 在 Python 3 中排序,例如:

<块引用>

>>>pprint.pprint(set(string.digits), width=1){'0','1','2','3','4','5','6','7','8','9'}

但是,在 Python 2 中,相同原始代码的输出是排序的:

<块引用>

>>>pprint.pprint(set(string.digits))设置(['0','1','2','3','4','5','6','7','8','9'])

我认为是 Python 3 和 Python 2 之间的不一致,以及单行多行行为之间的不一致,导致了这个错误.

对于 dicts,一个类似的例子说明了输出在 Python 3 或 2 中的排序,因为它应该是:

>>>pprint.pprint({i:None for i in set(string.digits)}){'0':无,1":无,2":无,3":无,4":无,5":无,6":无,7":无,8":无,9":无}

但是,对于 Python 3.6,pprintdict 进行排序可能会令人惊讶,因为它们 已现在订购.但是,由于这只是一个实现细节(目前),我想 pprint 没有义务维护插入顺序(还),这样做会破坏 pprint始终对 dicts 进行排序的 Python 版本的自身一致性.

I know that dicts and sets aren't ordered, so equal sets or dicts may print differently (all tests with Python 3.6.1):

>>> for obj in {0, 8}, {8, 0}, {0:0, 8:8}, {8:8, 0:0}:
        print(obj)

{0, 8}
{8, 0}
{0: 0, 8: 8}
{8: 8, 0: 0}

And I just realized that pprint ("pretty-print") sorts dicts but not sets:

>>> for obj in {0, 8}, {8, 0}, {0:0, 8:8}, {8:8, 0:0}:
        pprint.pprint(obj)

{0, 8}
{8, 0}
{0: 0, 8: 8}
{0: 0, 8: 8}

It's documentation also says "Dictionaries are sorted by key before the display is computed". But why doesn't it also sort sets? Doesn't seem pretty to me. And is there a way to make it sort sets? Also inside nested structures, as that's a main purpose of pprint.

解决方案

This was raised in issue 27495 and it is a bug, rather than just a design choice, but apparently has not yet been resolved.

Here is another example from the issue that illustrates perhaps more obviously the behavior you identify in Python 3:

>>> import string, pprint
>>> pprint.pprint(set(string.digits))
{'7', '1', '9', '8', '3', '0', '2', '5', '6', '4'}

The same applies for frozenset() too, but note that multi-line pprint outputs are sorted in Python 3, for example:

>>> pprint.pprint(set(string.digits), width=1)
{'0',
 '1',
 '2',
 '3',
 '4',
 '5',
 '6',
 '7',
 '8',
 '9'}

However, in Python 2, the output from the same original code is sorted:

>>> pprint.pprint(set(string.digits))
set(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'])

I think it is the inconsistency between Python 3 and Python 2, and between the single-line multi-line behavior, that makes this a bug.

For dicts, a similar example, illustrates as you note, that the output is sorted in either Python 3 or 2, as it should be:

>>> pprint.pprint({i:None for i in set(string.digits)})
{'0': None,
 '1': None,
 '2': None,
 '3': None,
 '4': None,
 '5': None,
 '6': None,
 '7': None,
 '8': None,
 '9': None}

However, for Python 3.6, it could be considered surprising that pprint sorts dicts since they are ordered now. However, since this is just an implementation detail (for now) I guess there is no obligation for pprint to maintain the insertion order (yet), and doing so would break pprint's own consistency across Python versions of always sorting dicts.

相关文章