在修改列表时迭代列表时出现令人惊讶的行为

时间:2017-12-20 11:31:37

标签: python list for-loop

我知道这是一个你永远不应该编写的代码示例,而且我并没有要求采用正确的方法。我担心的是我不了解它的行为,所以我希望有人可以解释它:

def foo(list_of_chars):
    '''Returns the set of words that can be obtained by removing one character from list_of_chars.'''
    result = set()
    my_copy = list(list_of_chars)
    for elem in my_copy:
        my_copy.remove(elem)
        result.add(''.join(my_copy))
        my_copy = list(list_of_chars)
    return result

我原本期望这个函数的行为(让我们说list_of_chars['h', 'e', 'l', 'l', 'o']):

  1. 代码运行完美,因为我们在每次迭代结束时恢复my_copy,所以当for循环将下一个元素分配给elem时,它就像我们从未触及列表一样(所以我们会反复思考' h,'' l',' l',' o') ;
  2. 代码失败了,因为循环结束时的分配被某种方式忽略了,所以我们先删除' h',跳过'删除' l&# 39 ;,跳过下一个' l',然后删除' o' - 可能会崩溃。
  3. 实际发生的事情是陌生人:我们遍历' h,' l',' l',' o',所以& #39; E'被跳过,但它是唯一被跳过的字符。其他示例的行为方式相同:只忽略list_of_chars的第二个元素。有人可以解释一下吗? (Python 2和3产生相同的结果)。

1 个答案:

答案 0 :(得分:4)

for循环在每次迭代时都不会再次“读取”my_copy,但my_copy.remove会这样做。

for elem in my_copy:
    my_copy.remove(elem)

在第一次迭代中,两行中的my_copy引用同一个对象。您实际上正在修改对象for迭代。但是,在迭代结束时,您将my_copy替换为其他内容。 for循环保留其原始对象引用,但my_copy.remove引用my_copy的当前版本。所以现在for循环迭代的对象和你remove元素的对象是两个不同的对象。

因此remove仅在第一次迭代时干扰循环。