繁体   English   中英

python字典中返回值的随机顺序

[英]Random order of returned values in python dictionary

我不明白这一点,它会困扰我直到我明白。

此 python 代码计算每个字符出现在 'message' 变量中的次数:

message = 'Some random string of words'

dictionary= {}

for character in message.upper():
    dictionary.setdefault(character,0)
    dictionary[character] = dictionary[character] + 1

print(dictionary)

如果您多次运行它,您会注意到计数每次都以看似随机的顺序返回。 为什么是这样? 我认为循环应该每次都从字符串的开头开始,并以一致的顺序返回值……但事实并非如此。 setdefault()print()upper()方法中是否存在一些影响字符串处理顺序的随机元素?

由于两件事:

  • 词典“没有订购”。 你当然得到一些订单,但它取决于键的哈希值等。
  • 您使用(单字符)字符串作为键,并且字符串哈希值是随机的 如果你print(hash(message))或者甚至只是print(hash('c'))那么你会看到不同的运行也不同。

因此,由于顺序取决于哈希值,并且哈希值从一次运行变为下一次运行,当然您可以获得不同的顺序。

另一方面,如果你在同一次运行中重复它,你可能会获得相同的顺序:

message = 'Some random string of words'
for _ in range(10):
    dictionary= {}
    for character in message:
        dictionary.setdefault(character,0)
        dictionary[character] = dictionary[character] + 1
    print(dictionary)

我只是跑了它,它按照预期打印了完全相同的订单十次。 然后我再次运行它,它打印了一个不同的顺序,但再次十次相同。 正如所料。

dict本质上是无序的。

Python文档

键和值以任意顺序迭代,这是非随机的,在Python实现中各不相同,并且取决于字典的插入和删除历史。

编辑

正确实现目标的代码的替代方法是使用OrderedCounter

from collections import Counter, OrderedDict

class OrderedCounter(Counter, OrderedDict):
    'Counter that remembers the order elements are first encountered'

    def __repr__(self):
        return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))

    def __reduce__(self):
        return self.__class__, (OrderedDict(self),)

message = 'Some random string of words'
print(OrderedCounter(message.upper()))

这是因为安全性而发生的。 当您编写任何外部用户可以提供最终在字典中的数据的应用程序时,您需要确保他们不知道散列的结果是什么。 如果他们这样做,他们可以确保他们提供的每个新条目将散列到同一个bin。 当他们这样做时,你最终得到的是“分摊的O(1) ”检索,而不是O(n) ,因为字典中的每个get()都会得到相同的bin,并且必须遍历其中的所有项目。 (或者可能更长时间考虑其他处理请求)

有关更多信息, 查看https://131002.net/siphash/siphashdos_appsec12_slides.pdf

几乎所有语言都通过在启动时生成随机数并将其用作散列种子来防止这种情况,而不是从某个预定义的数字(如0

实现dict的方式是为了使查找快速有效。 即使dict的大小增加。 在引擎盖下,这意味着密钥顺序可能会改变。

如果键的顺序对您很重要,请尝试使用collectionsordereddict

由于 Python 3.7 词典现在是按插入顺序排列的文档

字典保留插入顺序。 请注意,更新密钥不会影响顺序。 删除后添加的键插入最后。

因此,您现在在问题中期望的预期行为是实际行为。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM