我不明白这一点,直到我这样做才会打扰我。
此python代码计算每个字符出现在'消息中的次数。变量:
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()
方法中是否存在一些影响字符串处理顺序的随机元素?
答案 0 :(得分:4)
由于两件事:
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)
,那么您也会看到不同的运行也不同。因此,由于顺序取决于哈希值,哈希值从一次运行变为下一次运行,当然您可以获得不同的顺序。
另一方面,如果您在同一次中重复,您可能会获得相同的订单:
.txt
我刚刚运行它并按预期打印完全相同的订单十次。然后我再次运行它,它打印了一个不同的顺序,但再次十次相同。正如所料。
答案 1 :(得分:2)
dict
本来就是无序的。
来自Python docs:
键和值以任意顺序迭代,这是非随机的,在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()))
答案 2 :(得分:2)
这是由于安全性而发生的。当您编写任何外部用户可以提供最终在字典中的数据的应用程序时,您需要确保他们不知道散列的结果是什么。如果他们这样做,他们可以确保他们提供的每个新条目将散列到同一个bin。当他们这样做时,您最终会使用O(1)
代替“{1}}”,因为字典中的每个O(n)
都会获得相同的bin,并且必须遍历所有项目它。 (或者可能更长时间考虑其他处理请求)
请查看https://131002.net/siphash/siphashdos_appsec12_slides.pdf以获取更多信息。
几乎所有语言都会通过在启动时生成一个随机数并将其用作哈希种子来阻止这种情况,而不是从某个预定义的数字开始,如get()
。
答案 3 :(得分:1)
实现dict
的方式旨在使查找快速有效。即使dict
的大小增加。在引擎盖下,这意味着密钥顺序可能会改变。
如果密钥的顺序对您很重要,请尝试使用ordereddict
中的collections
。