迭代my_dict.keys()并修改字典中的值会使迭代器失效吗?

时间:2016-06-07 20:16:31

标签: python iterator undefined-behavior

我的例子是这样的

for my_key in my_dict.keys():
    my_dict[my_key].mutate()

是否定义了上述代码的行为(假设my_dict是字典而mutate是一个改变其对象的方法)?我担心的是,改变字典中的值可能会使字典的键上的迭代器无效。

另一方面,keys方法的Python documentation表示它返回一个列表。如果是这样,我应该(我认为)能够改变字典的值,并且只要我不改变,添加或删除任何键,仍然可以安全地访问字典的每个元素。这是对的吗?

3 个答案:

答案 0 :(得分:6)

是的,这是安全的,至少在所有基于C的Python实现中都是如此。它也是安全的:

for my_key in my_dict: # NOTE:  no .keys() here
    my_dict[my_key].mutate()

也就是说,安全性并不依赖于实现密钥列表,并且通常更有效的是不要仅仅为了遍历密钥而调用.keys()

修改

请注意,在迭代期间完全替换与现有密钥关联的值也很好:

for my_key in my_dict:
    my_dict[my_key] = something_new()

文档可以更清楚地了解这一点;-) 不是在迭代期间删除或添加密钥可预测的安全性。你对这些价值观所做的事情并不重要。

答案 1 :(得分:1)

是。这不是特定于Python,字典,甚至是基于散列的数据结构。

字典的内部结构完全基于其键。如果更改键周围的键可以更改字典的结构,如果在直接在字典上迭代的过程中发生,则迭代行为将变为未定义。特别是如果您想在迭代期间添加或删除键,那么您将使用.keys()来避免实际迭代字典以避免此问题。如果你改变一个键就会完全被破坏,因此不允许使用可变的内置类型作为字典键。

但字典并不关心价值观。它们对存储或结构没有任何影响。它们只是一个侧面细节,是实现的一个微不足道的部分。它特别不关心你是否改变了这些值 - 实际上它无法知道你这样做了。

这应该不足为奇。这是你迭代的关键。您可以按键存储内容,然后按键检索它们。您检查密钥是否为in字典,如果不是,您可能会获得KeyError。值只是位于键旁边的那些东西,因此可以在找到键时找到并返回它们。

类似地,您可以迭代列表并在执行此操作时更改或替换其值,但不要追加或删除任何内容,因为这会影响内部结构。列表的索引就像它的键。

但是,您无法触摸集合的值,因为在集合中,键和值扮演相同的角色。

答案 2 :(得分:0)

该文件还说:

  

字典的值可以是任何类型,但键必须是不可变的数据类型,如字符串,数字或元组。

所以,你根本不能改变它们。