当前位置: 首页 > 面试题库 >

Python-为什么字典和集合中的顺序是任意的?

叶鸿
2023-03-14
问题内容

我不明白在python中如何通过“任意”顺序循环遍历字典或集合。 我的意思是,这是一种编程语言,所以语言中的一切都必须100%确定,对吗?Python必须有某种算法来决定选择字典或集合的哪个部分,1,2等等。
我错过了什么?


问题答案:

顺序不是任意的,而是取决于字典或集合的插入和删除历史,以及特定的Python实现。对于这个答案的其余部分,对于"dictionary",你还可以读取"set"set被实现为只有键而没有值的字典

对键进行散列,并将散列值分配给动态表中的插槽(它可以根据需要增长或收缩)。映射过程可能导致冲突,这意味着必须根据已存在的键将密钥插入下一个插槽。

列出内容循环遍历插槽,因此键以它们当前在表中的顺序列出。

以键'foo''bar'为例,假设表的大小为8个插槽。在Python 2.7中,hash('foo')is -4177197833195190597,hash('bar')is 327024216814240868。模数8,这意味着这两个键分别插入插槽3和4中,然后:

>>> hash('foo')
-4177197833195190597
>>> hash('foo') % 8
3
>>> hash('bar')
327024216814240868
>>> hash('bar') % 8
4

这通知了他们的上市顺序:

>>> {'bar': None, 'foo': None}
{'foo': None, 'bar': None}

除3和4之外的所有插槽均为空,在表上循环时首先列出插槽3,然后列出插槽4,因此’foo’在之前列出’bar’。

bar和baz,但是散列值恰好相距8,因此映射到完全相同的插槽4:

>>> hash('bar')
327024216814240868
>>> hash('baz')
327024216814240876
>>> hash('bar') % 8
4
>>> hash('baz') % 8
4

现在,他们的顺序取决于首先插入哪个密钥。第二个密钥将必须移至下一个插槽:

>>> {'baz': None, 'bar': None}
{'bar': None, 'baz': None}
>>> {'bar': None, 'baz': None}
{'baz': None, 'bar': None}

此处的表顺序有所不同,因为一个或另一个键先插入插槽。

CPython使用的基础结构(最常用的Python实现)的技术名称是哈希表,该哈希表使用开放式寻址。如果你感到好奇,并且对C足够了解,请查看C实现的所有(详细记录)细节。你还可以观看Brandon Rhodes在Pycon 2010上所作的有关CPython如何dict工作的演示,或者获取Beautiful Code的副本,其中包括Andrew Kuchling撰写的有关实现的章节。

请注意,从Python 3.3开始,还使用了随机的哈希种子,从而使哈希冲突无法预测,以防止某些类型的拒绝服务(攻击者通过引起大量哈希冲突而使Python服务器无响应)。这意味着给定字典的顺序也取决于当前Python调用的随机哈希种子。

其他实现可以自由地为字典使用不同的结构,只要它们满足已记录的Python接口,但我相信到目前为止,所有实现都使用哈希表的变体。

CPython 3.6引入了一个新的 dict实现,该实现可以维护插入顺序,并且启动起来更快,内存效率更高。新的实现没有保留一个大的稀疏表,其中的每一行都引用了存储的哈希值以及键和值对象,而是添加了一个较小的哈希数组,该数组仅引用密集表中的索引(一个索引仅包含实际行数键值对),而密集表恰好按顺序列出了包含的项。有关更多详细信息,请参见Python-Dev的建议。请注意,在Python 3.6中,这被认为是实现细节,Python语言不指定其他实现必须保留顺序。这在Python 3.7中有所更改,其中的详细信息是提升为语言规范 ; 为了使任何实现与Python 3.7或更高版本正确兼容,必须复制此保留顺序的行为。

Python 2.7及更高版本还提供了一个OrderedDict类,该类的子类dict添加了额外的数据结构来记录键顺序。以某种速度和额外的内存为代价,此类会记住你按什么顺序插入键。然后列出键,值或项目将按此顺序进行。它使用存储在其他词典中的双向链接列表来使订单保持最新状态。请参阅Raymond Hettinger的帖子,概述该想法。请注意,该set类型仍然是无序的。

如果你需要订购的套装,则可以安装oset软件包;它适用于Python 2.5及更高版本。



 类似资料:
  • 如果我们想表示一组允许重复并且保留插入顺序的单个对象,那么我们应该使用List。 这里,插入顺序指的是什么?

  • 问题内容: 码: 打印。我不确定该方法如何确定l中关键字的顺序。但是,我希望能够以“适当”的顺序检索关键字。当然,正确的顺序将创建列表。 和这个: 问题答案: 你可以使用OrderedDict(需要Python 2.7)或更高版本。 另外,请注意,由于dict你使用进行创建的操作已经忘记了元素的顺序,因此该操作无效。相反,你想使用。 如文档中所述,对于低于python 2.7的版本,你可以使用此配

  • 问题内容: 我正在寻找一个有序的关联数组,即有序的字典的可靠实现。我想要按键而不是插入顺序排序。 更准确地说,我正在寻找一种int-to-float(或另一种用例是string-to-float)映射结构的节省空间的实现,该结构的结构是: 有序迭代为O(n) 随机访问为O(1) 我想到的最好的方法是将字典和键列表粘合在一起,使最后一个键按等分和插入顺序排列。 还有更好的主意吗? 问题答案: “随机

  • 问题内容: 我首先来看看Python Wikibook 中的python语言。 对于集,提到了以下内容: 我们还可以循环移动一组中的每个项目。但是,由于集合是无序的,因此无法确定迭代将遵循的顺序。 和给出的代码示例是: 输出: 当我运行该程序时,无论运行多少次,我都将以相同的顺序获得结果。如果集合是无序的并且迭代的顺序是不确定的,为什么它以相同的顺序返回集合?订单的依据是什么? 问题答案: 它们不

  • 问题内容: D = {‘a’: 1, ‘b’: 2, ‘c’: 3} >>> D 我只是在Python shell中进行了此操作,我想知道为什么键“ c”会在键“ b”之后??? 问题答案: 顺序与它们内部的工作方式以及它们在哈希表中的顺序有关。这又取决于键的哈希值,键的插入顺序以及所使用的Python实现。 该顺序是任意的(但不是随机的),知道它将是哪个顺序将永远不会有用。 要获取排序的键列表,

  • 本文向大家介绍什么是Python中的顺序表,包括了什么是Python中的顺序表的使用技巧和注意事项,需要的朋友参考一下 1、顺序表介绍 顺序表是最简单的一种线性结构,逻辑上相邻的数据在计算机内的存储位置也是相邻的,可以快速定位第几个元素,中间不允许有空,所以插入、删除时需要移动大量元素。顺序表可以分配一段连续的存储空间Maxsize,用elem记录基地址,用length记录实际的元素个数,即顺序表