为什么python字典对于python3.7是不可逆的?


11

从3.7开始,保证标准的python词典保持插入顺序。(*)

d = {'b': 1, 'a': 2}
for k in d: 
    print(k)
# Prints always 'b' before 'a'.

换句话说,字典键会严格保持顺序。原则上,这将允许密钥是可逆的。但是,以下任何一项均无效:

# TypeError: 'dict' object is not reversible
for k in reversed(d): 
    print(k)

# TypeError: 'dict_keys' object is not reversible
for k in reversed(d.keys()): 
    print(k)

问题:此行为背后的原因是什么?为什么没有使命令具有可逆性?将来有什么计划改变这种行为?

解决方法当然可以:

for k in reversed(list(d.keys())): 
    print(k)

(*)作为事实上,这种情况已经为Python 3.6的典型安装,如在讨论这个职位


更新:从python 3.8字典开始实际上是可逆的。可接受的答案是指Guido与其他导致该决定的核心开发人员之间的讨论。简而言之,他们根据实现工作和用户的实际利益对语言的一致性进行了加权。

Answers:


5

文档

反转seq

返回反向iterator。seq必须是具有__reversed__()方法或支持序列协议的对象(该__len__()方法和__getitem__()整数参数从0开始的方法)。

一个dict对象没有实现__reversed__。它确实实现了后两种方法。但是,__getitem__将键作为参数而不是整数(从0开始)作为参数。

至于为什么,这已经在这里提出和讨论

编辑:

这些引号来自Python-Dev邮件列表(线程“为dict添加__reversed__方法”,始于25. 05. 18),我将从“概念性”参数开始,第一个来自Antoine Pitrou:

OrderedDict已经支持reversed()毫无价值。该论点有两种可能:

  1. dict现在类似于OrderedDict,因此它也应该支持reversed()。

  2. 您可以使用OrderedDict明确表示您关心订购;无需添加任何内容即可。

我的想法是,保证常规词典的插入顺序是全新的,因此该概念要花一段时间才能融入词典,成为日常思考的一部分。一旦发生这种情况,可能不可避免会出现用例,并在某个时候添加__reversed__。该实现似乎很简单,并且期望有限的有序集合是可逆的并不是很大的概念飞跃。

随后是Raymond Hettinger的回复:

鉴于该命令现在可以跟踪插入顺序,因此想知道最近的插入(即遍历任务命令中最新添加的任务)似乎是合理的。其他可能的用例可能与我们使用Unix tail命令的方式相对应。

如果出现了这些用例,那么已经支持__reversed__很好,这样人们就不会试图通过popitem()调用并重新插入来实现丑陋的解决方法。

邮件列表中表达的主要关注点,至少在某些实现中,这会增加过多的膨胀或降低内存效率(必须具有双链表而不是单链表),这是Inada Naoki引用Python Bug Tracker的话(发行33462)):

“下订单”并不意味着“可逆”。例如,单个链表是有序的,但不可逆。

虽然CPython实现可以提供有效的__reverse__,但添加__reverse__意味着所有 Python实现都可以提供它。例如,某些Python实现可能能够使用hashmap +单个链表实现dict。如果__reverse__添加了,就不可能了。

返回邮件列表,这是最后两条消息(均发布于08.06.2018)。首先是迈克尔·塞里克(Michael Selik):

我的说法是对v3.8的共识是+1吗?

该线程的最后一点是INADA Naoki研究了各种实现,并确定可以在3.8中包括此功能。据我了解,Guido同意INADA的建议,等待MicroPython实现v3.7。由于INADA改变了主意,我猜这一切都对吗?

总结Guido van Rossum的信息:

对我来说听起来不错。在这种情况下,我们将有两个版本:

  • 3.6在CPython中但在语言规范中实现了保留顺序的位置

  • 3.7在语言规范中也添加了它

如其他答案和评论中所述,reversed()自3.8(14.10.2018)版本以来,字典和字典视图均受支持。


5
您的第二个引用似乎是从该线程中选择的偏见。共识似乎是该功能将在3.8中添加。同样在python 3.7之前,根本没有对普通dict对象进行排序(至少不能从语言中保证),所以reversed也没有任何意义
FlyingTeller

我在战斗中没有狗,我只是引用了他的第一反应。但是您是对的,观点很好-我删除了引号。
gst

1
谢谢。python-dev的讨论线程正在揭示。实际上,该功能已经在两天前(2019年10月14日)发布的python 3.8中实现。
normanius


docs引用无济于事,它只是乞求下一个问题“所以,为什么dict类型的工具不能实现__reversed__?”。python-dev链接具有有用的内容,但相关部分应直接在答案中重现(因为此类异地链接可能会腐烂)。
WIM


1

python 3.8更新

Dict和dictviews现在可以使用reversed()以反向插入顺序进行迭代

>>> dict = {1: "1", 2: "2", 3: "3"}
>>> reversed(dict)
<dict_reversekeyiterator object at 0x7f72ca795130>

这个答案是否贡献了其他答案,评论或问题本身尚未涵盖的新内容?
normanius

@normanius它有一个lil可视代码示例,可能对快速浏览器有用
jamylak
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.