我知道在迭代列表时不允许删除元素,但允许在迭代时将元素添加到python列表中.这是一个例子:
for a in myarr:
if somecond(a):
myarr.append(newObj())
Run Code Online (Sandbox Code Playgroud)
我在我的代码中尝试了这个并且似乎工作正常,但是我不知道是不是因为我很幸运并且它将来会在某个时候破坏?
编辑:我不喜欢复制列表,因为"myarr"很大,因此它太慢了.另外,我需要用"somecond()"检查附加的对象.
编辑:在某些时候"somecond(a)"将是假的,因此不会有无限循环.
编辑:有人问过"somecond()"函数.myarr中的每个对象都有一个大小,每次"somecond(a)"为真,并且一个新对象被附加到列表中,新对象的大小将小于a."somecond()"有一个关于小物体如何的epsilon,如果它们太小,它将返回"false"
小智 49
你为什么不用惯用的C方式呢?这应该是防弹的,但它不会很快.我很确定索引到Python中的列表会走链表,所以这是一个"Shlemiel the Painter"算法.但是,在明确特定部分代码确实存在问题之前,我倾向于不担心优化.首先让它工作; 然后担心如果必要的话,让它快速.
如果要迭代所有元素:
i = 0
while i < len(some_list):
more_elements = do_something_with(some_list[i])
some_list.extend(more_elements)
i += 1
Run Code Online (Sandbox Code Playgroud)
如果您只想迭代最初在列表中的元素:
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
Run Code Online (Sandbox Code Playgroud)
Roh*_*nga 20
好吧,根据http://docs.python.org/tutorial/controlflow.html
修改循环中迭代的序列是不安全的(这只能发生在可变序列类型中,例如列表).如果您需要修改正在迭代的列表(例如,复制所选项目),则必须迭代副本.
You could use the islice from itertools to create an iterator over a smaller portion of the list. Then you can append entries to the list without impacting the items you're iterating over:
islice( myarr, 0, len(myarr)-1 )
Run Code Online (Sandbox Code Playgroud)
Even better, you don't even have to iterate over all the elements. You can increment a step size.
You can do this.
bonus_rows = []
for a in myarr:
if somecond(a):
bonus_rows.append(newObj())
myarr.extend( bonus_rows )
Run Code Online (Sandbox Code Playgroud)
简而言之:如果您完全确定所有新对象都无法通过somecond()检查,那么您的代码可以正常工作,只是浪费了一些时间来迭代新添加的对象。
在给出正确的答案之前,您必须了解为什么在迭代时更改列表/命令是一个坏主意。使用forstatement时,Python请尽量聪明一些,并每次返回一个动态计算的项目。以list为例,python记得有一个指标,每一次返回l[index]给你。如果要更改l,结果l[index]可能会很混乱。
注意:这是一个stackoverflow问题,以证明这一点。
在迭代时添加元素的最坏情况是无限循环,请在python REPL中尝试以下操作(如果不能读懂错误,请尝试以下操作):
import random
l = [0]
for item in l:
l.append(random.randint(1, 1000))
print item
Run Code Online (Sandbox Code Playgroud)
它将不间断地打印数字,直到内存用完或被系统/用户杀死为止。
了解内部原因,让我们讨论解决方案。这里有一些:
迭代原始列表,然后修改复制的列表。
result = l[:]
for item in l:
if somecond(item):
result.append(Obj())
Run Code Online (Sandbox Code Playgroud)
您可以决定如何迭代列表,而不是处理对python的控制:
length = len(l)
for index in range(length):
if somecond(l[index]):
l.append(Obj())
Run Code Online (Sandbox Code Playgroud)
迭代之前,请计算列表长度,仅计算循环length时间。
无需修改原始列表,而是将新对象存储在新列表中,然后将它们连接起来。
added = [Obj() for item in l if somecond(item)]
l.extend(added)
Run Code Online (Sandbox Code Playgroud)