Python For Loop List Interesting Result

前端 未结 4 1911
执念已碎
执念已碎 2021-01-25 07:42
a = [0,1,2,3,4,5]
for b in a:
  print \":\"+str(b)
  a.pop(0)

Thinking that this would work in order going through the entire list and all its items I

相关标签:
4条回答
  • 2021-01-25 08:05

    At each iteration of the for loop we have to check the condition b in a So when you start:

    a = [0,1,2,3,4,5]
    for b in a:
      print ":"+str(b)
      a.pop(0)
    

    b = 0 and in a (meaning elements in a) is 5. Now you print the stringified version of a[b] then remove the first element of the array. Thus iteration two becomes:

    a = [1, 2, 3, 4, 5]
    b = 1 (it incremented)
    size of a = 4 (it shrank)
    

    Next they'll be b=2, size of a becomes 3. The final iteration which would have produced the out of bounds errors you were expecting, won't occur then because b will be larger than the size of the array, so we're done.

    0 讨论(0)
  • 2021-01-25 08:16

    You are looping over a list and altering it at the same time. By using .pop() you are shortening the list, but the iterator pointer is not updated.

    Use a copy instead:

    for b in list(a):
    

    or

    for b in a[:]:
    

    where the [:] slice notation returns a list copy.

    Another approach would be to use a while loop instead:

    while a:
        print a.pop(0)
    

    because an empty list tests as boolean False.

    The python for loop uses it's argument as an iterator, it does not itself keep an index. There is no way for the for loop to 'know' you removed elements. Instead, it's the list() iterator that keeps that pointer:

    >>> a = [0,1,2,3,4,5]
    >>> itera = iter(a)
    >>> itera.next()  # index 0 -> a[0] is 0
    0
    >>> a.pop(0)
    0
    >>> a
    [1,2,3,4,5]
    >>> itera.next()  # index 1 -> a[1] is 2
    2
    

    That iterator keeps a counter, and every time you call next() on the iterator it'll give you the value at the next index, whatever that value may be, until the counter is equal to the current lenght of the list.

    0 讨论(0)
  • 2021-01-25 08:17

    If you want to use .pop() in a loop, a common idiom is to use it with while:

    a = [0,1,2,3,4,5]
    while a:
      print ":{}".format(a.pop(0))
    

    Or, if you want the printed pattern you have there:

    a = [0,1,2,3,4,5]
    while a:
        print ":{}\n{}".format(a[0],a.pop(0))
    

    prints

    :0
    0
    :1
    1
    :2
    2
    :3
    3
    :4
    4
    :5
    5
    
    0 讨论(0)
  • 2021-01-25 08:24

    This is completely "expected" and documented behavior. When you iterate over the list, you're basically iterating over memory locations. When you pop something out of the list, everything after that in the list moves 1 index closer to the start of the list. Hence, you end up skipping items. Iteration stops when you reach the end of the list.

    Typically when doing something like this, you want to iterate over a copy of the list:

    for b in a[:]:
        ...
    

    As indicated in the comments, if you iterate over the list in reversed order:

    for b in reversed(a):
        a.pop()
    

    This works as intended because you are constantly pulling off the final element and therefore you're not shifting the position in the list of any of the elements that you haven't yet seen.

    0 讨论(0)
提交回复
热议问题