我的脚本中有这个代码来执行霍夫曼编码:
def huffmanEncoding(freqDict):
for key in freqDict.keys():
freqDict[HuffmanTree(value=key)] = freqDict.pop(key)
...
我想要做的是用一个树节点替换字典中的每个键,树节点的值是原始键。 HuffmanTree类正常工作。
然而,这段代码有很奇怪的行为。使用调试工具,我发现有时某些键被处理了两次或更多次,这意味着它们首先被转换为树节点,然后再次转换,使用其当前树节点作为新树节点的值。
我用下面显示的代码替换了我的代码:
def huffmanEncoding(freqDict):
keys = list(freqDict.keys())
for key in keys:
freqDict[HuffmanTree(value=key)] = freqDict.pop(key)
现在它正常工作。但有人可以解释为什么我的第一个版本有这么奇怪的行为?如果我想更改字典中的所有键,我应该总是使用第二个版本吗?
答案 0 :(得分:7)
您在迭代时向字典添加键和删除键。这意味着order of the keys also can change。
通常情况下,Python会在执行此操作时引发异常,但由于每次迭代都要删除并添加一个键,因此引发该异常的内部检查无法检测到您在迭代时进行了更改。
迭代键视图的副本:
def huffmanEncoding(freqDict):
for key in list(freqDict):
freqDict[HuffmanTree(value=key)] = freqDict.pop(key)
list()
调用将所有键复制到单独的列表对象。而不是迭代live view of the dictionary keys,而是迭代静态不变的列表。从原始字典中弹出键也不会从列表副本中删除这些键,设置新键也不会导致列表获得更多键。这使循环完全稳定。
答案 1 :(得分:0)
第二个表单将从字典中获取所有键,并将其转换为列表。此列表未连接到字典,因此更改字典中的键不会更改该列表。
在第一种形式中,keys
返回一个迭代器(它将动态生成值),因此更改字典可能会导致您在for循环中添加的键被keys
迭代器返回
始终使用第二种形式。