【问题标题】:I know python dict is order less but why I am getting keys in same order "always"我知道 python dict 的顺序较少,但为什么我“总是”以相同的顺序获取密钥
【发布时间】:2014-06-30 04:18:42
【问题描述】:

我有一个名为tmpdict

>>> tmp
{1: 'ONE', 2: 'TWO', 3: 'THREE'}
>>> type(tmp)
<type 'dict'>

我对这个dict 进行了二十次迭代,在所有迭代中,我都以相同的顺序获得了键列表。

>>> for i in range(20):
...   print tmp.keys()
... 
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]

我知道 python dict 的顺序较少但是为什么我得到的密钥“总是”顺序相同

【问题讨论】:

  • 顺序未指定......这并不意味着随机。

标签: python dictionary


【解决方案1】:

您不会在调用 tmp.keys() 之间修改 tmp,因此键的顺序永远不会改变。

From the docs:

如果调用items()keys()values()iteritems()iterkeys()itervalues(),而没有对字典进行干预修改,则列表将直接对应。这允许使用zip()pairs = zip(d.values(), d.keys()) 创建(value, key) 对。 iterkeys()itervalues() 方法具有相同的关系:pairs = zip(d.itervalues(), d.iterkeys()) 为对提供相同的值。创建相同列表的另一种方法是pairs = [(v, k) for (k, v) in d.iteritems()]

【讨论】:

    【解决方案2】:

    否则,这是行不通的:

    for key, value in zip(d.keys(), d.values()):
        ...
    

    还有各种类似的问题。

    Python 的 dict 和 set 类型保证具有相同的迭代顺序只要 dict/set 没有被修改。尝试将其他值添加到 tmp,下次您可能会得到不同的订单。

    (然而,请注意,作为键的小整数并不是其工作原理的一个特别好的示例——小整数在 CPython 中会自行散列,因此它们可能更有可能以数字形式出现顺序。尝试一些字符串。)

    【讨论】:

    • 但是,这样做更容易:for i,j in d.items()
    • 是的,但有时您想对键和值做一些更有趣的事情,无论出于何种原因。 (反正你觉得dict.items是怎么实现的?)
    【解决方案3】:

    在创建字典后,python 会创建自己的顺序。每次调用.keys().values().items() 时,只要不修改字典,每次都会得到无序的相同 顺序的结果。希望这是有道理的。

    正如您在下面的示例中看到的,即使我使用特定顺序创建字典,python 也会重新排序字典。但是,在那之后,顺序始终保持不变(只要您不修改字典)。

    a = {'apple' : 'fruit', 'car' : 'vehicle', 'onion' : 'vegetable'}
    
    print a
    
    for i in range(5):
        print a.keys()
    
    [OUTPUT]
    {'car': 'vehicle', 'apple': 'fruit', 'onion': 'vegetable'}
    ['car', 'apple', 'onion']
    ['car', 'apple', 'onion']
    ['car', 'apple', 'onion']
    ['car', 'apple', 'onion']
    ['car', 'apple', 'onion']
    

    【讨论】:

    • 这与效率无关;这只是哈希表的本质。
    • 这并不完全是“Python 认为最有效的顺序”,它只是一个带有基本键冲突例程的哈希表。如果稍后的插入或删除导致 dict 被调整大小,则插入后的顺序可能会发生变化。但是,是的,对于一个稳定状态的 dict,条目将保持相同的顺序,至少在 CPython 中是这样(尽管它实际上是解释器的实现细节,不是语言规范所保证的)。
    • 语言绝对保证修改之间的顺序是稳定的:docs.python.org/2/library/stdtypes.html#dict.items
    • 我真的需要重申,订单并不总是保持不变。如果字典被扩展或缩小到足以让解释器调整底层哈希表的大小,则顺序可以很好地改变。
    【解决方案4】:

    由于python dict是作为Hash Table实现的,所以key的顺序是根据它的hash值来决定的,这决定了使用哪个slot来存储'key/value'对。

    整数值作为key,hash值就是整数本身

    >>> map(hash, [1,2,3])
    [1,2,3]
    

    这里你使用的key是连续的int,它们的哈希值也是连续的,下面的哈希算法很有可能选择连续的槽来存储“键/值”对,这就是为什么你看到的顺序与你创建字典。下面是一个简单的反例:

    >>> tmp = {1:1, 5:5, 10:10}
    >>> tmp.keys()
    [1, 10, 5]
    

    当然,在循环期间,您不会修改字典,这不会导致哈希表调整大小,因此顺序保持不变。

    >>> for i in range(5):
    ...   print tmp.keys()
    [1, 10, 5]
    [1, 10, 5]
    [1, 10, 5]
    [1, 10, 5]
    [1, 10, 5]
    

    如果您对 Python 中的详细实现感兴趣,请查看这篇不错的文章: Python dictionary implementation

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-08-01
      • 1970-01-01
      • 2017-01-12
      • 1970-01-01
      • 2016-04-17
      • 2019-09-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多