【问题标题】:Why does appending to a list break my for loop? (Python)为什么附加到列表会破坏我的 for 循环? (Python)
【发布时间】:2012-05-20 22:13:38
【问题描述】:
for family in city.familyList:
    for member in family.membersList:
        if member.sex == "male":
            if member.status == "eligible":
                print "There were", len(family.membersList), "members of family", family.familyName
                family.membersList.remove(member)
                print "Now there are", len(family.membersList), "members of family", family.familyName
                member.status = "needs a wife"
                print member.firstName, member.status
                print "There were", len(city.familyList), "families"
                city.familyList.append(Family(member.lastName, member))
                print "Now there are", len(city.familyList), "families"

使用此代码,我试图遍历家庭成员列表,找到 18 岁以上的男性,将他们从家庭中移除,并建立自己的家庭。如果我在循环末尾注释掉附加,它可以正常工作(当然,不会增加家庭的数量)。如果我执行追加,这就是它的样子:

Ticking Disan
There were 5 members of family Evnes
Now there are 4 members of family Evnes
Gregor needs a wife
There were 6 families
Now there are 7 families
There were 7 members of family Bhworth
Now there are 6 members of family Bhworth
Ewan needs a wife
There were 7 families
Now there are 8 families

debugger.run(setup['file'], None, None)
  File "C:\Users\Mark\Desktop\eclipse-SDK-3.7.2-win32\eclipse\plugins\org.python.pydev.debug_2.5.0.2012040618\pysrc\pydevd.py", line 1060, in run

pydev_imports.execfile(file, globals, locals) #execute the script
  File "C:\Users\Mark\workspace\WorldPop\WorldPop.py", line 610, in <module>
    main()
  File "C:\Users\Mark\workspace\WorldPop\WorldPop.py", line 74, in main
    done = menu()
  File "C:\Users\Mark\workspace\WorldPop\WorldPop.py", line 77, in menu
    genWorld()
  File "C:\Users\Mark\workspace\WorldPop\WorldPop.py", line 116, in genWorld
    dispWorld(oneWorld)
  File "C:\Users\Mark\workspace\WorldPop\WorldPop.py", line 135, in dispWorld
    displayTick(world)
  File "C:\Users\Mark\workspace\WorldPop\WorldPop.py", line 317, in displayTick
    calcMarriage(city)
  File "C:\Users\Mark\workspace\WorldPop\WorldPop.py", line 359, in calcMarriage
    for member in family.membersList:
TypeError: iteration over non-sequence

我意识到,当 for 循环循环回到起点以搜索新的 memberList 时,问题就出现了,我只是不明白为什么执行附加会破坏循环。非常感谢任何见解。

【问题讨论】:

  • 您是否有机会提供行号来匹配错误?它死在哪一条线?你能用 ipython 之类的东西来查看它正在死去的数据结构的状态吗?
  • 首先,我认为遍历列表并从循环内部更改它不是一个好主意。其次,我怀疑当你在city.familyList.append(Family(member.lastName, member)) 中创建一个新的Family 时,它的memberList 出于某种原因不是一个正确的列表。可能Family.__init__ 有错误?
  • 啊,是的,通常familyList是一个类对象的数组,而新创建的族只是接收类对象,而不是单元素数组中的类对象。 ——这就是问题所在!谢谢!

标签: python loops append


【解决方案1】:

一般来说,修改您正在迭代的集合是一个非常糟糕的主意(您既要从family.membersList 中删除,又要添加到city.familyList)。

根据您正在迭代的数据结构和迭代算法,更改迭代集合可能会导致项目被跳过或多次查看。我认为大多数情况下这是不安全的,除非文档明确说明。

【讨论】:

  • 我能想到的一个例外是链表。如果迭代器只保存当前链接,则删除该链接或在之前/之后插入不应破坏迭代器。
【解决方案2】:

您要附加的新Family 实例具有membersList 属性,但它不支持迭代(for/in)。这就是您收到此异常的原因。

即使在修复了这个问题之后,您还是会通过在迭代序列时修改序列来为自己准备好惊喜。试试这个:

for family in city.familyList[:]:
    for member in family.membersList[:]:
        # ...

[:] 切片语法创建每个列表的副本,因为它存在于循环的开头。对原始列表的修改不会影响副本,因此在循环执行过程中不会有任何意外。

如果您确实需要在for 循环中包含在for 循环中找到/创建的新项目,我建议迭代Queue.Queue 对象并将每个对象插入到该队列中进行探索。当没有新的探索时,队列将为空并且循环将停止。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-11
    • 2018-12-18
    • 2019-01-12
    • 1970-01-01
    • 1970-01-01
    • 2020-10-04
    • 2021-03-14
    • 2014-11-25
    相关资源
    最近更新 更多