python在for循环之前冻结列表吗?

时间:2012-03-01 11:30:09

标签: python for-loop

说我有一个列表l和一个线程 t1 永远迭代l

while True:
    for i in l:
        #do something

另一个帖子 t2 随机修改或删除l中的成员。

删除后会发生什么? t1 会检测到当前循环中的内容吗?

更新

  1. 冻结我的意思是 t1 获得l的副本。 t2 可以修改l 确定

  2. 引用文档或简单但有说服力的代码段 欢迎。

3 个答案:

答案 0 :(得分:7)

没有。列表没有被冻结 - 你的迭代器在引发异常的意义上不会“破坏”。相反,它将继续在列表中前进,结果可能令人惊讶。

请考虑以下代码(此处为ideone的代码段:http://ideone.com/0iMao):

l = list(range(10))
for i in l:
    print i
    try:
        del l[i]
    except (RuntimeError,IndexError), e:
        print e

print l

它产生这个输出:

0
2
4
5
7
list assignment index out of range
9
list assignment index out of range
[1, 2, 4, 5, 7, 9]

这可能不是您想要或期望的,尽管它显然定义明确:http://docs.python.org/reference/compound_stmts.html#the-for-statement

相反,您可以锁定列表,也可以复制一份。请注意,iter(l)不会在内部进行复制,并且与直接迭代列表具有相同的效果。

答案 1 :(得分:2)

以下是您可以观察到的事情:

>>> from threading import Thread
>>> from time import sleep
>>> liszt = ['first item', 'second item', 'third item', 'fourth item',
...         'plentee more items', "but I'm lazy"]
>>> def thread_one():
...     for i in liszt:
...             print 'Thread one found "%s"' % i
...             sleep(1)
... 
>>> def thread_two():
...     sleep(0.5)
...     print 'Thread two deleting first item.'
...     del liszt[0]
...     sleep(1)
...     print 'Thread two deleting fourth item.'
...     del liszt[3]
... 
>>> Thread(target=thread_one).start(); Thread(target=thread_two).start()
Thread one found "first item"
Thread two deleting first item.
Thread one found "third item"
Thread two deleting fourth item.
Thread one found "fourth item"
Thread one found "but I'm lazy"

从中你可以看到修改一个线程中的列表会影响另一个线程中的迭代器;删除第一个项目使迭代器跳过一个项目,删除未来的项目意味着它将不会在迭代器中看到,因为它已经消失。

以下是一些如何运作的模型;我没有明确地为此提供代码,但你可以通过观察来解决这个问题。

State:             [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Iterator position:  ^

转到下一个项目。

State:             [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Iterator position:     ^

删除第一项。

State:             [2, 3, 4, 5, 6, 7, 8, 9, 10]
Iterator position:     ^

转到下一个项目。

State:             [2, 3, 4, 5, 6, 7, 8, 9, 10]
Iterator position:        ^

删除第五项。

State:             [2, 3, 4, 5, 7, 8, 9, 10]
Iterator position:        ^

等等。在线程问题上,无论您是在一个线程还是多个线程中执行它都无关紧要。当然,您可能在项目是否被删除时遇到竞争条件,但它仍然以相同的方式运作。

如果您不熟悉迭代的内部,请联系iter。事实上,for x in y正在迭代iter(y)。因此,如果需要,您可以使用iter(liszt) listiterator对象,同时使用next(),同时调整其迭代的列表。比交互式Python控制台中的for循环更方便。

答案 2 :(得分:0)

该列表可从两个线程访问,而不是冻结。 迭代器将“知道”成员已被删除并跳过它们,除非您具有超出列表长度的显式索引访问权限。 删除本身是线程安全的。

如果您想要真正锁定列表,请使用互斥锁保护或复制它。