Python List Problem (now Solved)

I was programming in Python when I had a strange problem. My program stores data in a list, with a length of at least three. Indices 0 and 1 contain other data, but from index 2 and higher, the list contains dictionaries. The program needs to process each of the dictionaries, but only if there is something in the dictionary. I want a list_of_n values that are the index numbers of dictionaries with stuff in them.

Here is attempt one, and the output it produces:

def test(d = [0, 0, {}, {}, {'a':4}]):
   list_of_n = range( 2, len(d) )
   print( '!!! Y\'arr, we got ' + str(list_of_n) + ' here!' )
   for n in list_of_n:
      print( '... checkin\' out ' + str(n) )
      if {} == d[n]:
         list_of_n.remove( n )
         print( '--> removing ' + str(n) )
      else:
         print( '--> keeping ' + str(n) )
>>> test()
 !!! Y'arr, we got [2, 3, 4] here!
 ... checkin' out 2
 --> removing 2
 ... checkin' out 4
 --> keeping 4

What happens to 3?

———————–

Here is attempt two, which works:

def test(d = [0, 0, {}, {}, {'a':4}]):
   list_of_n = []
   for n in xrange( 2, len(d) ):
      print( '... checkin\' out ' + str(n) )
      if {} != d[n]:
         list_of_n.append( n )
         print( '--> adding ' + str(n) )
      else:
         print( '--> not adding ' + str(n) )
>>> test()
 ... checkin' out 2
 --> not adding 2
 ... checkin' out 3
 --> not adding 3
 ... checkin' out 4
 --> adding 4

———————–

Now, I admit that the second version is better than the first, and that I should have chosen it in the first place. But why doesn’t the first version work? What happens to 3?

Advertisements

6 Comments

  1. You change the object to iterate on in the first version, this is something that is not supposed to work as expected. Here is a different implementation of the first version, that might make it more obvious, of what seems to happen:

    def test(d = [0, 0, {}, {}, {‘a’:4}]):
    list_of_n = range( 2, len(d) )
    print( ‘!!! Y\’arr, we got ‘ + str(list_of_n) + ‘ here!’ )
    i = 0
    while i removing ‘ + str(n) )
    else:
    print( ‘–> keeping ‘ + str(n) )
    i += 1

  2. You modify the list you’re iterating over. Thou shalt not do that!
    When it comes to the second iteration, n is assigned the 2nd list element, which is – since the “2” was removed during the first iteration – the second element of the list [3, 4].

  3. Thanks for your comments. For me at least, this was one of those neat moments where we encounter the subtle differences between how a human thinks of a problem and how a computer thinks of the same problem. My Python Quest continues!

  4. There are a lot of problems with your code most of which are typical newcomer errors.

    def test(d = [0, 0, {}, {}, {‘a’:4}]):

    This defines mutable default value which will be the same between invocations of you function. If you ever change d inside your function it will persist which is not what you typically intend.

    list_of_n = range( 2, len(d) )
    for n in list_of_n:

    This is typical loop written by people not accustomed to python’s iterate-over-collection power. First, there is a nice enumerate function which return (index, element) pairs making most loops look better. Second, there are list comprehensions which allow you to clearly express operations on iterables.

    As others said already, changing list while iterating is wrong. So here is pythonic version of your function:

    def test(d=None):
    if d is None:
    d = [0, 0, {}, {}, {‘a’:4}]
    return [index for index, element in enumerate(d) if element]

  5. In this case, the default argument was for demonstration purposes, so it didn’t cause a problem in the real method. But… I have been caught up in dictionary mutability!

    Especially thanks for showing what a list comprehension is, because I’ve seen them before, but not knowing what they’re called, I tried finding it in the “for” documentation.

    For anybody (or myself) finding this post in the future, the official Python tutorial talks about list comprehensions here: http://docs.python.org/tutorial/datastructures.html#list-comprehensions

Comments are closed.