为什么我的Python字典是有序的?

3

我想看一下Twitter上一个单词在推文中出现的频率。我使用Twitter API下载了500条推文,并创建了一个字典,其中单词频率作为键,对应该频率下所有单词的列表作为值。

我一直以为字典是无序的,所以我想以某种方式排序我的字典。但当我查看它时,它已经按键从低到高排序了。这怎么可能?

这是我使用的代码:

def countWords(cleanDict):
    reverseDict = {}
    FreqDict = {}
    count = 1
    for tweet_id in cleanDict:
        tweet = cleanDict[tweet_id]
        wordList = tweet.split()
        for word in wordList: # Creates a dictionary with words as keys and
                              # frequencies as values
            if word in reverseDict:
                reverseDict[word] += 1
            else:
                reverseDict[word] = 1
    for word in reverseDict: # Creates a dictionary with frequencies as keys and
                             # lists of words as values
        if reverseDict[word] in FreqDict:
            temp = FreqDict[freqDict[word]]
            temp.append(word)
            FreqDict[freqDict[word]] = temp
        else:
            FreqDict[freqDict[word]] = [word]
    return FreqDict

countWords(cleanDict) # cleanDict is a dictionary with tweet ID's as keys and
                      # tweets as values

别误会我; 我的字典已经像这样排序了,但是为什么呢? 是我添加到字典中的方式导致的吗?

我尝试使用整数作为键和一些字符串作为值创建一个字典。我没有按任何特定顺序添加键,但当我打印这个字典时,它又按键排序了。 这是 Python 总是这样做的吗?


它们下载的顺序是什么? - Drewdin
1
你怎么“知道”它是有序的?你在哪里查看它?它是如何显示的?底层表示是无序的,但这并不意味着其他东西不能以有序的方式表示它。 - g.d.d.c
@Drewdin 下载的最后一条推文是最后发布的推文。倒数第二条下载的是倒数第二个发布的推文,以此类推直到第500条推文。 - EerlijkeDame
@g.d.d.c 我刚刚把它打印到我的终端上了。 - EerlijkeDame
2个回答

8
“Unordered” 是一个用词错误;它们是任意排序的,由实现决定。具体而言,排序保证是任意的,但是一致的(在Python解释器的单个实例内[1])。关于为什么会出现这种行为,原因是您在使用整数作为键。恰好在CPython中,一个整数的哈希值就是它本身。因此,这段代码:
d = dict(zip(range(100),' '*100))
print(d)

由于实现细节的原因,将始终按数字顺序输出键。 但是这样做:

d = dict((L, i) for i, L in enumerate('abcdefg'))
print(d)

很可能不会按字母顺序打印出来。


[1] 字符串哈希行为可能会因解释器实例的不同而有所不同,这取决于您正在运行的Python版本。 Python 3引入了一种“随机种子”来哈希字符串键,作为一种安全措施。 您可以使用python -R在Python 2.7上启用该行为。


1
值得注意的是,即使使用整数,只有在数字相对密集且接近零时,您才有可能获得精确的排序。如果您在示例中使用不同于0100的范围,则可能会得到无序键。例如,dict(zip(range(200, 300), " "*100))从键256开始,而不是从200开始。 - Blckknght
哦,太奇怪了。我没有意识到在Python 2中它不会像在Python 3中那样工作。发生这种情况的原因是哈希值(等于键)跨越底层哈希表大小的精确倍数。实际的哈希表索引是哈希值模表大小,这意味着一些值最终会无序。我怀疑在Python 2中也可能以某种方式发生相同的事情,除非有一些故意的黑客攻击使其保持有序,但我不知道。对于分布非常广泛的数字,由于哈希冲突,您可能会得到奇怪的顺序! - Blckknght
@Blckknght 有趣。我昨晚考虑了一下,你是对的 - 对于py3中的小字典,排序似乎与key%256一致,即8位哈希表。我刚刚检查了一下,下一步是10位表,因此是key%1024。所以真正的异常是python 2 - 我很好奇继续调查,如果我自己无法解决问题,可能会发布一个问题。 - roippi
啊,就是这个了——dict(zip(range(1000,2100), ' '*1100))在Python 2中表现出key % 2048的排序方式。因此实际上只是哈希表在py2中从11位开始,在py3中从8位开始。呼。 - roippi
它取决于您在字典中放置的值的数量。尝试使用少于6个项目的字典,以及键为7和8,您将在Python 2和3中迭代时先获得8而不是7。我认为我们在版本之间看到的差异与导致内部哈希表调整大小的确切边界有关(或者可能是调整大小的表变大了多少)。 - Blckknght

1

这可能只是纯粹的运气。如果字典中有更多对象需要调整大小,或者对象不是一个接一个地创建(因此它们的ID / 内存地址变化更大),那么情况可能会改变。

如果您需要顺序,可以简单地使用collections.OrderedDict并保证它。或者使用collections.Counter来完成此任务,该计数器专门用于此类计数。


这难道不可能只是纯粹的运气吧?如果只有10条推文,那么字典中的顺序实际上可能是有序的,但是500条呢? - EerlijkeDame

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接