在迭代时向列表添加元素

84 投票
12 回答
158679 浏览
提问于 2025-04-16 04:22

我知道在遍历一个列表的时候是不允许删除元素的,但在遍历时添加元素到 Python 列表中是否可以呢?下面是一个例子:

for a in myarr:
    if somecond(a):
        myarr.append(newObj())

我在代码中试过这个,似乎运行得很好,但我不知道这是不是因为我运气好,未来会不会出问题?

我不想复制这个列表,因为 myarr 非常大,这样会太慢。而且我需要用 somecond() 来检查添加的对象。

在某个时刻,somecond(a) 会返回假值,所以不会出现无限循环。

每个 myarr 中的对象都有大小,每次 somecond(a) 返回真时,如果往列表中添加一个新对象,这个新对象的大小会比 a 小。somecond() 有一个阈值,规定了对象可以有多小,如果对象太小,它会返回“假”。

12 个回答

28

根据 http://docs.python.org/tutorial/controlflow.html 的说法,

在循环中修改正在遍历的序列是不安全的(这只会发生在可变序列类型,比如列表)。如果你需要修改正在遍历的列表(比如,复制选定的项目),你必须遍历一个副本。

65

你为什么不直接用C语言的标准方式来做呢?这样做应该是非常稳妥的,但速度可能会慢。我记得在Python中,访问列表的元素时会遍历整个链表,所以这就像是“涂鸦的画家”算法。不过我通常不会太担心优化,直到某段代码真的出现问题。先让它能正常工作;如果有必要,再考虑怎么让它跑得更快。

如果你想遍历所有的元素:

i = 0  
while i < len(some_list):  
  more_elements = do_something_with(some_list[i])  
  some_list.extend(more_elements)  
  i += 1  

如果你只想遍历最初在列表中的元素:

i = 0  
original_len = len(some_list)  
while i < original_len:  
  more_elements = do_something_with(some_list[i])  
  some_list.extend(more_elements)  
  i += 1
12

你可以使用 islice 这个工具,它来自 itertools,来创建一个只包含列表中一部分的迭代器。这样,你就可以在不影响你正在遍历的那些项目的情况下,往列表里添加新的内容:

islice(myarr, 0, len(myarr)-1)

更棒的是,你甚至不需要遍历所有的元素。你可以设置一个步长,逐步增加。

撰写回答