当您尝试在遍历列表元素时删除它会发生什么
What happens when you try to delete a list element while iterating over it
我正在按如下方式迭代列表:
some_list = [1, 2, 3, 4]
another_list = [1, 2, 3, 4]
for idx, item in enumerate(some_list):
del some_list[idx]
for item in another_list:
another_list.remove(item)
当我打印出列表的内容时
>>> some_list
[2, 4]
>>> another_list
[2, 4]
我知道 Python 不支持在迭代时修改 list
,正确的方法是迭代列表的副本。但我想知道幕后到底发生了什么,即为什么上面代码片段的输出是 [2, 4]
?
您可以使用自制的迭代器来显示(在本例中 print
s)迭代器的状态:
class CustomIterator(object):
def __init__(self, seq):
self.seq = seq
self.idx = 0
def __iter__(self):
return self
def __next__(self):
print('give next element:', self.idx)
for idx, item in enumerate(self.seq):
if idx == self.idx:
print(idx, '--->', item)
else:
print(idx, ' ', item)
try:
nxtitem = self.seq[self.idx]
except IndexError:
raise StopIteration
self.idx += 1
return nxtitem
next = __next__ # py2 compat
然后在您要检查的列表周围使用它:
some_list = [1, 2, 3, 4]
for idx, item in enumerate(CustomIterator(some_list)):
del some_list[idx]
这应该说明在那种情况下会发生什么:
give next element: 0
0 ---> 1
1 2
2 3
3 4
give next element: 1
0 2
1 ---> 3
2 4
give next element: 2
0 2
1 4
虽然它只适用于序列。映射或集合更复杂。
I want to know what exactly happens behind the scenes
我们知道,列表中的每个项目都有自己唯一的索引;这是有序的,从 0 开始。如果我们删除一个项目,那么索引大于我们删除的项目的任何项目现在都被向下移动。
这就是重要的原因:
foo = ['a', 'b', 'c', 'd']
for index in range(len(foo)):
del foo[index]
在这个循环中,我们将删除所有元素,所以我们应该以 foo == []
结束,对吧?不是这种情况。在我们第一次循环中,我们删除索引 0
处的项目,索引 1
处的项目成为索引 0
处的项目.下一次循环时,我们删除 索引 1
处的项目,它是 之前索引 2.[=26 处的项目=]
在前两次迭代中,我们从数组中删除了 'a'
和 'c'
,*但我们忽略了删除 'b'
。一旦我们到达第三次迭代(虽然我们会删除索引 2
), 不再是索引 2
处的元素;只有索引 0
和 1
。当我们尝试删除索引 2
处不存在的项时会引发异常,并且循环会停止。结果是一个损坏的数组,如下所示:['a', 'd']
.
我正在按如下方式迭代列表:
some_list = [1, 2, 3, 4]
another_list = [1, 2, 3, 4]
for idx, item in enumerate(some_list):
del some_list[idx]
for item in another_list:
another_list.remove(item)
当我打印出列表的内容时
>>> some_list
[2, 4]
>>> another_list
[2, 4]
我知道 Python 不支持在迭代时修改 list
,正确的方法是迭代列表的副本。但我想知道幕后到底发生了什么,即为什么上面代码片段的输出是 [2, 4]
?
您可以使用自制的迭代器来显示(在本例中 print
s)迭代器的状态:
class CustomIterator(object):
def __init__(self, seq):
self.seq = seq
self.idx = 0
def __iter__(self):
return self
def __next__(self):
print('give next element:', self.idx)
for idx, item in enumerate(self.seq):
if idx == self.idx:
print(idx, '--->', item)
else:
print(idx, ' ', item)
try:
nxtitem = self.seq[self.idx]
except IndexError:
raise StopIteration
self.idx += 1
return nxtitem
next = __next__ # py2 compat
然后在您要检查的列表周围使用它:
some_list = [1, 2, 3, 4]
for idx, item in enumerate(CustomIterator(some_list)):
del some_list[idx]
这应该说明在那种情况下会发生什么:
give next element: 0
0 ---> 1
1 2
2 3
3 4
give next element: 1
0 2
1 ---> 3
2 4
give next element: 2
0 2
1 4
虽然它只适用于序列。映射或集合更复杂。
I want to know what exactly happens behind the scenes
我们知道,列表中的每个项目都有自己唯一的索引;这是有序的,从 0 开始。如果我们删除一个项目,那么索引大于我们删除的项目的任何项目现在都被向下移动。
这就是重要的原因:
foo = ['a', 'b', 'c', 'd']
for index in range(len(foo)):
del foo[index]
在这个循环中,我们将删除所有元素,所以我们应该以 foo == []
结束,对吧?不是这种情况。在我们第一次循环中,我们删除索引 0
处的项目,索引 1
处的项目成为索引 0
处的项目.下一次循环时,我们删除 索引 1
处的项目,它是 之前索引 2.[=26 处的项目=]
在前两次迭代中,我们从数组中删除了 'a'
和 'c'
,*但我们忽略了删除 'b'
。一旦我们到达第三次迭代(虽然我们会删除索引 2
), 不再是索引 2
处的元素;只有索引 0
和 1
。当我们尝试删除索引 2
处不存在的项时会引发异常,并且循环会停止。结果是一个损坏的数组,如下所示:['a', 'd']
.