为什么循环跳过列表中的项目?

时间:2015-03-11 14:26:58

标签: python for-loop try-catch

当我运行下面的代码时,似乎只迭代列表中工作人员总数的一半。然后跳转到关闭父进程。

我非常困惑,为什么下面的代码没有迭代列表中的所有项目,也许我已经盯着这个太长时间才能看到明显的?任何帮助将不胜感激。

这是控制台。

Waiting...
[u'worker-1.15579', u'worker-1.15575', u'worker-1.15577', u'worker-1.15570', u'worker-1.15573', u'worker-1.15168', u'worker-1.15170']
The terminate_pid is 15561
Process was SUCCESSFULLY closed.
Process was SUCCESSFULLY closed.
Process was SUCCESSFULLY closed.
no process found with pid 15170
Process was already closed.
Closed terminator window.

以下是代码,

            workers_to_be_restarted = [u'worker-1.14524', u'worker-1.14526', u'worker-1.14518', u'worker-1.14528', u'worker-1.14522']

            for item in workers_to_be_restarted:
                if this_machine == item.split('.')[0]:
                    if not terminate_pid:
                        try:
                            terminate_pid = psutil.Process(psutil.Process( int(item.split('.')[1]) ).ppid()).ppid()
                            print "The terminate_pid is {}".format(str(terminate_pid))
                        except Exception, e:
                            terminate_pid = None
                            print e
                            pass
                    try:
                        print "Terminating {}".format(item)
                        p = psutil.Process( int(item.split('.')[1]) )
                        p.terminate()
                        time.sleep(1)
                        print "Process was SUCCESSFULLY closed."
                        workers_to_be_restarted.remove( item )
                    except Exception, e:
                        print e
                        time.sleep(1)
                        print "Process was already closed."
                        workers_to_be_restarted.remove( item )
                        pass
            try: #THE ABOVE SEEMS TO BE EXITING HERE before looping through all the items!? NOT SURE WHY?
                if terminate_pid:
                    p = psutil.Process( terminate_pid )
                    p.terminate()
                    print "Closed terminator window."
                    worker_restart['restart'] = None
                    worker_restart['workers_to_be_restarted'] = workers_to_be_restarted

2 个答案:

答案 0 :(得分:2)

当您修改要迭代的列表时会发生这种情况:

foo = [1, 2, 3, 4, 5]

for each in foo:
    if each == 2:
        foo.remove(each)

    print each


>>> 1
>>> 2
>>> 4
>>> 5

要解决此问题,您可以将列表复制到新列表中,并从副本中删除(而不是您正在迭代的那个):

foo = [1, 2, 3, 4, 5]
bar = list(foo)

for each in foo:
    if each == 2:
        bar.remove(each)

    print each

print bar

>>> 1
>>> 2
>>> 3
>>> 4
>>> 5
>>> [1, 3, 4, 5]

答案 1 :(得分:2)

看起来你只是迭代一部分的原因是因为workers_to_be_restarted.remove( item )。这实际上是删除了列表中的 next 项,而不是您要删除的项。例如:

workers_to_be_restarted = [u'worker-1.14524', u'worker-1.14526', u'worker-1.14518', u'worker-1.14528', u'worker-1.14522']
for item in workers_to_be_restarted:
    print(item)
    workers_to_be_restarted.remove(item)

<强> 输出:

worker-1.14524
worker-1.14518
worker-1.14522

正如您所看到的,第二个和第四个工作人员正在被移除而在迭代其他人。 要解决此问题,请对列表进行复制并首先对其进行迭代。我会用一个完整的列表切片分配替换你当前的行,如下所示:

for item in workers_to_be_restarted[:]:

<强> 输出:

worker-1.14524
worker-1.14526
worker-1.14518
worker-1.14528
worker-1.14522