[Tutor] list method help

Danny Yoo dyoo at hkn.eecs.berkeley.edu
Thu Feb 2 20:52:50 CET 2006



On Thu, 2 Feb 2006, Michael Haft wrote:

>           was just trying to do something and tried the following code:
>
> list = ["1", "test", "1.5"]
>
> for x in list:
>      print list.pop(x)
>
> I get the following error:
>
> print list.pop(x)
> TypeError: an integer is required


Hi Michael,

The error message is accurate: list.pop() is only supposed to take an
integer.

If we take a look at the documentation of list.pop(), we should be able to
see why:

    http://www.python.org/doc/lib/typesseq-mutable.html

The problem is one of us being confusing about the domain that pop() takes
in.  pop() is supposed to take in the position of the element we're trying
to pop, not the element itself.  Does this make sense?




> Does this mean i can't use a for loop to pop things from a list? or is
> there another way to do it?
>
> I also tried the following:
>
> list = ["1", "test", "1.5"]
>
> for x in list:
>      print list.pop(0)
>
> which worked but returned the following:
>
> 1
> test
>
> Why did it not return the last value in the list?

Simultaneous for-loop iteration and removal from a list is fraught with
subtle issues.  What's going on is that the for-loop expects all the
elements to stay in place.  In the example above, imagine an arrow aimed
at a particular element of a list:

    ["1", "test", "1.5"]
      ^

During iteration, the arrow moves across the list till it hits the end of
the list.  Note, though, that list.pop(0) pulls elements toward the left:

    ["test", "1.5"]
       ^

and if the arrow naively marches forward, as in regular list iteration:

    ["test", "1.5"]
               ^

and we pop(0) again, then we again push the remaining element forward:

    ["1.5"]
              ^

but our arrow's out of the list's range!  So we're done iterating across
the list's structure, and this "premature" exit is what you're seeing.


It's this interplay between the shifting behavior of pop(0) with the
obliviousness of the iterator that causes these subtle issues.  This is
not really a Python-specific issue, but a fundamental one involving
mutation across a list.  (For example, Java has the same issues, and
that's why Java's Iterator has a remove() method to attack this specific
issue.)

One way to get around this is to not use an iterator, but to use a
different condition that's more stable under shifting, like checking for
list length:

    while len(mylist) != 0:
       ...

or we can pop() starting backwards, from the end of the list, which can
less disruptive to the list's structure than pop()ping from the front.


Just out of curiosity, though, what are you trying to do?  Why pop()
altogether?  It might be that you can solve whatever problem you're doing
with very little list mutation.  Tell us more about what you're trying to
do, and we can give more help.

Good luck!



More information about the Tutor mailing list