nor*_*ius 9 dictionary python-3.x
从3.7开始,保证标准的python词典保持插入顺序。(*)
d = {'b': 1, 'a': 2}
for k in d:
print(k)
# Prints always 'b' before 'a'.
Run Code Online (Sandbox Code Playgroud)
换句话说,字典键会严格保持顺序。原则上,这将允许密钥是可逆的。但是,以下任何一项均无效:
# 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)
Run Code Online (Sandbox Code Playgroud)
问题:此行为背后的原因是什么?为什么没有使命令具有可逆性?将来有什么计划改变这种行为?
解决方法当然可以:
for k in reversed(list(d.keys())):
print(k)
Run Code Online (Sandbox Code Playgroud)
(*)作为事实上,这种情况已经为Python 3.6的典型安装,如在讨论这个职位。
更新:从python 3.8字典开始实际上是可逆的。可接受的答案是指Guido与其他导致该决定的核心开发人员之间的讨论。简而言之,他们权衡了语言一致性,实现工作和用户的实际利益。
从文档:
反转(seq)
返回一个反向
iterator。seq 必须是具有__reversed__()方法或支持序列协议的对象(该__len__()方法和__getitem__()具有从 0 开始的整数参数的方法)。
一个dict对象没有实现__reversed__. 它确实实现了后两种方法。但是,__getitem__将键作为参数,而不是整数(从 0 开始)。
至于为什么,这里已经提出并讨论了这一点。
编辑:
这些引用来自Python-Dev 邮件列表(线程“为 dict 添加 __reversed__ 方法”,开始于 25. 05. 18),我将从“概念性”参数开始,第一个来自 Antoine Pitrou:
OrderedDict 已经支持 reversed() 毫无价值。争论可以双向进行:
dict 类似于现在的 OrderedDict,所以它也应该支持 reversed();
您可以使用 OrderedDict 明确表示您关心排序;无需向 dict 添加任何内容。
我的想法是,常规 dicts 的保证插入顺序是全新的,所以这个概念需要一段时间才能适应并成为日常思考 dicts 的一部分。一旦发生这种情况,可能不可避免地会出现用例并且 __reversed__ 会在某个时候被添加。实现看起来很简单,期望有限有序集合是可逆的并不是一个概念上的飞跃。
随后是雷蒙德·赫廷格 (Raymond Hettinger) 的回复:
鉴于 dicts 现在跟踪插入顺序,想要知道最近的插入(即在任务 dict 中循环最近添加的任务)似乎是合理的。其他可能的用例可能对应于我们如何使用 Unix tail 命令。
如果出现这些用例,最好已经支持 __reversed__ ,这样人们就不会试图使用 popitem() 调用然后重新插入来实现丑陋的解决方法。
邮件列表中表达的主要问题是,至少在某些实现中,这会增加过多的膨胀或降低内存效率(必须有双链表而不是单链表),这里是 Inada Naoki 来自 Python 错误跟踪器的引用(问题 33462 ):
“有订单”并不意味着“可逆”。例如,单链表是有序的,但不可逆。
虽然 CPython 实现可以提供高效的
__reverse__,但添加__reverse__意味着所有Python 实现都应该提供它。例如,某些 Python 实现可能能够使用 hashmap + 单链表实现 dict。如果__reverse__添加,则不再可能。
回到邮件列表,这是最后两条消息(均于 2018 年 6 月 8 日发布)。首先来自迈克尔塞利克:
我说的共识是 +1 以包含在 v3.8 中是否正确?
线程中的最后一点是 INADA Naoki 研究了各种实现并决定可以在 3.8 中包含此功能。据我了解,Guido 同意 INADA 的建议,即等待 MicroPython 实施 v3.7。既然稻田改变了主意,我猜这一切都是赞成的?
以 Guido van Rossum 的信息结束:
这对我来说听起来很正确。然后我们将有两个版本,情况就是这样:
3.6 在 CPython 中实现顺序保留但在语言规范中
3.7 它也被添加到语言规范中
正如其他答案和评论中所述,reversed()自 3.8 版(14.10.2018)起支持 dicts 和 dictviews。