gpt4 book ai didi

python - 在 Python 中使用枚举遍历列表时是否应该创建副本

转载 作者:太空宇宙 更新时间:2023-11-04 09:41:15 26 4
gpt4 key购买 nike

回答this question时,我遇到了一些我在 Python 中从未想过的事情(由用户指出)。

基本上,我已经知道(这里有一个有趣的 thread 关于它)我必须在 Python 中更改列表时进行迭代时制作副本,以避免出现奇怪的行为。

现在,我的问题是,使用 enumerate 是否可以解决这个问题?

test_list = [1,2,3,4]
for index,item in enumerate(test_list):
if item == 1:
test_list.pop(index)

这段代码会被认为是安全的还是我应该使用,

for index,item in enumerate(test_list[:]):

最佳答案

首先,让我们回答你的直接问题:

enumerate 在这里没有任何帮助。它的工作方式就好像它持有一个指向底层可迭代对象的迭代器(并且,至少在 CPython 中,这正是它所做的),所以任何用列表迭代器做的不合法或不安全的事情都是不合法或不安全的使用环绕该列表迭代器的枚举对象。


您的原始用例 - 设置 test_list[index] = new_value - 在实践中是安全的 - 但我不确定它是否保证是安全的。

您的新用例——调用 test_list.pop(index)——可能安全。


列表迭代器最明显的实现基本上只是对列表的引用和对该列表的索引。因此,如果您在当前位置或该位置的左侧插入或删除,您肯定会破坏迭代器。例如,如果您删除 lst[i],这会将所有内容从 i + 1 移动到最后一个位置,因此当您移动到 ​​i + 1,您将跳过原始的 i + 1 值,因为它现在是第 i。但如果你在当前位置的右侧插入或删除,那不是问题。

由于 test_list.pop(index) 在当前位置或左侧删除,即使使用此实现也不安全。 (当然,如果您仔细编写了您的算法,以便在命中后跳过该值无关紧要,甚至可能很好。但更多的算法将无法处理。)

可以想象,Python 实现可以将原始指针存储到用于列表存储的数组中的当前位置。这意味着插入 任何地方 可能会破坏迭代器,因为插入会导致整个列表重新分配到新内存。如果实现有时会在收缩时重新分配列表,那么也可以在任何地方删除。我不认为 Python 不允许执行所有这些操作,因此如果您想变得偏执,在迭代时从不插入或删除可能更安全。

如果您只是替换现有值,很难想象在任何合理的实现下这会如何破坏迭代器。但是,据我所知,语言引用和 list 库引用1 实际上并未对列表迭代器的实现做出任何 promise 。2

因此,您是否关心“在我的实现中安全”、“在每个迄今为止编写的每个实现中安全”、“在每个可以想象的(对我来说)实现中安全”还是“通过引用保证安全”取决于您".

我认为大多数人都乐于在迭代过程中替换列表项,但要避免缩小或增加列表。但是,肯定有生产代码至少会删除迭代器的右侧。


1。我相信 教程 只是在某处说在迭代时永远不要修改任何数据结构——但这就是教程。始终遵循该规则当然是安全的,但遵循不太严格的规则也可能是安全的。

2。除非 key 函数或任何其他尝试在 sort 中间以任何方式访问列表。 ,结果未定义。

关于python - 在 Python 中使用枚举遍历列表时是否应该创建副本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51601249/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com