在python中为什么
列表对可以在for循环中被修改且不报错,
但字典集合在python被修改一次后就会报错。
我想知道他们在内存层面的缘由。哪位大佬来告诉我这个小白呀
先祭出一点代码:
a = list(range(9))
b = set(a)
c = {}.fromkeys(a, 0)
for i in a:
# 经测试 可以在for循环里面修改列表a的值 但有可能会导致死循环,以至程序混乱不受控制。
a.append(randint(1, 100))
# 经测试 不可以在for循环里面修改集合b的值 ,一旦修改,情况和字典差不多。
# b.add(randint(1, 100))
# 经测试 不可以在for循环里面修改字典c的值 ,一旦修改,下次循环就会报错
# c[str(randint(1, 100))] = randint(1, 100)
print(f'容器对象 c 的内容为: {a}')
我觉得这个问题还挺好的。
python3.6之前的DictObject在实现的时候,内在的数据结构是一个无序hashmap,而hashmap的数据是存在一个可变长数组里的(关于这点可以去找找其他文章)。我们在用for循环遍历的时候,其实是在遍历这个数组,而由于插入的顺序和遍历的顺序并不一致,如果我们在遍历数组过程中数组发生了变化,我们无法知道插入的数据是在当前迭代器位置的前还是后,这会导致循环的逻辑完全无法预测:插入在迭代器位置之后,会多循环一次,在当前位置之前,会循环不到。所以python在实现Dict的迭代器时做了以下限制:每次调用next方法时,检查迭代器上记录的数组大小和字典实际的大小是否一致,不一致则直接报错。
按照这个限制,我们可以得出,其实不是不可以在循环过程中更改Dict,而是不能在改变Dict之后继续调用next方法进行循环,所以下面的代码是可以运行的:
python3.7之后的DictObject用一个辅助数组实现了有序的Dict(这个也可以去找下文章,不赘述了),不过这个限制仍然保留了下来。