1
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"

With this code I am attempting to iterate through a list of family members, locate males over 18, remove them from their family, and start their own family. If I comment out the append at the end of the loop it works fine (without increasing the number of families, of course). This is what it looks like if I perform the append:

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

I realize that the problem comes when the for loop cycles back to the beginning to search through a new memberList, I just don't see why performing the append is breaking the loop. Any insight is greatly appreciated.

3
  • Any chance you can provide line numbers to match up the errors? Which is the final line it's dying on? Can you use something like ipython to see the status of the data structure it's dying on? Commented May 12, 2012 at 18:18
  • 1
    First, I don't think iterating over a list and changing it from inside the loop is a good idea. Second, I suspect that when you create a new Family in city.familyList.append(Family(member.lastName, member)), its memberList is not a proper list for some reason. Maybe there's a bug in Family.__init__? Commented May 12, 2012 at 18:20
  • Ah, yes, usually familyList is an array of class objects, whereas newly created families simply receive the class object, rather than the class object in a one-element array. -- This was the problem! Thank you! Commented May 12, 2012 at 19:03

2 Answers 2

2

Your new Family instance that you're appending has a membersList attribute, but it does not support iteration (for/in). That's why you receive this exception.

Even after fixing that, you are setting yourself up for surprises by modifying the sequences while iterating over them. Try this:

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

The [:] slice syntax creates a copy of each list as it exists at the start of the loop. Modifications made to the original lists will not affect the copy, so there won't be any surprises during loop execution.

If you really need to include new items found/created during the for loop in the for loop, I recommend iterating over a Queue.Queue object and inserting each object to explore into that queue. When there's nothing new to explore the queue will be empty and the loop will stop.

Sign up to request clarification or add additional context in comments.

Comments

1

In general it's a really bad idea to modify the collection you're iterating through (you're both removing from family.membersList and adding to city.familyList).

Depending on the data structure that you're iterating over, and on the iteration algorithm, changing the iterated collection might cause items to be either skipped or seen more than once. I'd assume this is unsafe most of the time, unless the docs explicitly say otherwise.

1 Comment

One exception I can think of is with linked lists. If the iterator only holds the current link, then removing that link or inserting before/after should not break the iterator.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.