Python for循环跳过其他所有循环?

jdi*_*son 4 python django

我有一个奇怪的问题.有人看到我的代码有什么问题吗?

for x in questions:
    forms.append((SectionForm(request.POST, prefix=str(x.id)),x))
    print "Appended " + str(x)
for (form, question) in forms:
    print "Testing " + str(question)
    if form.is_valid():
        forms.remove((form,question))
        print "Deleted " + str(question)
        a = form.save(commit=False)
        a.audit = audit
        a.save()                
    else:
        flag_error = True
Run Code Online (Sandbox Code Playgroud)

结果是:

Appended Question 50
Appended Question 51
Appended Question 52
Testing Question 50
Deleted Question 50
Testing Question 52
Deleted Question 52
Run Code Online (Sandbox Code Playgroud)

它似乎跳过问题51.它被附加到列表中,但for循环跳过它.有任何想法吗?

Jus*_*ier 12

您正在修改forms正在迭代的对象的内容,当您说:

forms.remove((form,question))
Run Code Online (Sandbox Code Playgroud)

根据声明Python文档for,这不安全(重点是我的):

Python中的for语句与您在C或Pascal中使用的语句略有不同.而不是总是迭代数字的算术级数(如在Pascal中),或者让用户能够定义迭代步骤和暂停条件(如C),Python的for语句迭代任何序列的项目(列表或字符串),按照它们出现在序列中的顺序.

修改循环中迭代的序列是不安全的(这只能发生在可变序列类型中,例如列表).如果您需要修改正在迭代的列表(例如,复制所选项目),则必须迭代副本.切片表示法使这特别方便:

for x in a[:]: # make a slice copy of the entire list
...    if len(x) > 6: a.insert(0, x)
Run Code Online (Sandbox Code Playgroud)

另请参阅Python语言参考中的这一段,它准确地解释了发生了什么:

当循环修饰序列时有一个微妙的变化(这只能发生在可变序列,即列表中).内部计数器用于跟踪下一个使用的项目,并在每次迭代时递增.当该计数器达到序列的长度时,循环终止.这意味着如果套件从序列中删除当前(或前一个)项目,则将跳过下一个项目(因为它获取已经处理的当前项目的索引).同样,如果套件在当前项目之前的序列中插入项目,则下次循环时将再次处理当前项目.

有很多解决方案.您可以按照他们的建议制作副本.另一种可能性是由于第二次for循环而创建一个新列表,而不是forms直接修改.这个选择由你...

  • @Marcin,它说不安全,不是不允许的.Python试图将用户视为负责任的成年人:如果你知道它不安全并且你选择继续进行,那么你自担风险,但是当它没有达到预期效果时就不要抱怨. (3认同)
  • @JustinEthier此行为在此处指定:http://docs.python.org/reference/compound_stmts.html#the-for-statement; 其他实现是否表现出相同的行为是它们符合规范的一个方面. (3认同)