2014-01-26 3 views

ответ

3

Обновление последовательности при Iterating имеет неожиданные результаты, поэтому его никогда не рекомендуют. На следующем рисунке показано, как переменная i изменяется каждый раз, когда вы перебирать во время выскакивают из списка

var Instruction     <--------- arr -------------> 
i         [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
|  for i in arr     ^
|____________________________________| 
|         | 
|         V 
|  arr.pop(0)     [1, 2, 3, 4, 5, 6, 7, 8, 9] 
|  
|  for i in arr     [1, 2, 3, 4, 5, 6, 7, 8, 9] 
|          ^
|_______________________________________| 
|_______________________________________| 
|          | 
|          V 
|  arr.pop(0)     [2, 3, 4, 5, 6, 7, 8, 9] 
|  
|  for i in arr     [2, 3, 4, 5, 6, 7, 8, 9] 
|          ^
|__________________________________________| 
|__________________________________________| 
|           | 
|           V 
|  arr.pop(0)     [3, 4, 5, 6, 7, 8, 9] 
|  
|  for i in arr     [3, 4, 5, 6, 7, 8, 9] 
|           ^
|_____________________________________________| 
|_____________________________________________| 
|            | 
|            V 
|  arr.pop(0)     [4, 5, 6, 7, 8, 9] 
|  
|  for i in arr     [4, 5, 6, 7, 8, 9] 
|            ^
|________________________________________________| 
|________________________________________________| 
|            | 
|            V 
|  arr.pop(0)     [5, 6, 7, 8, 9] 
4

Не рекомендуется изменять последовательность (или отображение) во время ее повторной передачи. Это будет беспорядочным указателем.

Например, следующий код никогда не будет завершен.

arr = [1,2,3] 
for i in arr: 
    print i 
    arr.append(i) 

В соответствии с for statement - NOTE:

Примечание: Существует тонкость, когда последовательность модифицируется с помощью петли (это может произойти только для изменяемых последовательностей, т.е. списки). Внутренний счетчик используется для отслеживания того, какой элемент используется далее, и это увеличивается на каждой итерации. Когда этот счетчик достиг , длина последовательности завершается. Это означает, что если набор удаляет текущий (или предыдущий) элемент из последовательности, следующий элемент будет пропущен (поскольку он получает индекс текущего элемента , который уже обработан). Аналогично, если в наборе вставлен элемент в последовательности перед текущим элементом, текущий элемент будет снова обработан в следующий раз через цикл. Это может привести к неприятным ошибок, которые можно избежать, сделав временную копию, используя кусочек всю последовательность, например,

for x in a[:]: 
    if x < 0: a.remove(x) 
1

Видимо, что вы whanted является:

for i in range(len(arr)): 
    arr.pop(0) 

Поскольку , как отметил @falsetru, изменение последовательности во время итерации не рекомендуется, но в этом примере цикл for основан на постоянном значении, то есть в размере arr. Каждый pop() удалит первый элемент, и список будет постепенно опустошен.

1

Это легче увидеть, что происходит путем добавления Перечислим:

for index,i in enumerate(arr): 
    if i in arr: 
     print(index,i) 
     arr.pop(0) 
print arr 

выходы:

(0, 0) 
(1, 2) 
(2, 4) 
(3, 6) 
(4, 8) 
[5, 6, 7, 8, 9] 

Popping изменяет длину массива, но индекс для итератора не обновляется, чтобы отразить это.

1

Позвольте мне показать вам, что происходит в коде:

# Initial position 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
#^
# i 

# Remove first 
[1, 2, 3, 4, 5, 6, 7, 8, 9] 
#^
# i 

# Move next 
[1, 2, 3, 4, 5, 6, 7, 8, 9] 
# ^
# i 

# Remove first 
[2, 3, 4, 5, 6, 7, 8, 9] 
# ^
# i 

# Move next 
[2, 3, 4, 5, 6, 7, 8, 9] 
#  ^
#  i 

# And so on... 

[4, 5, 6, 7, 8, 9] 
#   ^
#    i 

# Remove first 
[5, 6, 7, 8, 9] 
#   ^
#    i 

# Move next 
# Oops, the end of the list 

# The result: 

[5, 6, 7, 8, 9] 

Давайте посмотрим, как это работает под капотом. Во-первых, нам нужно итератора:

# for i in arr: 

In [30]: it = iter(arr) 

In [31]: it 
Out[31]: <listiterator at 0x130f9d0> 

И мы будем называть next(it), пока она не поднимается StopIteration исключение. Итак, давайте сделаем это:

In [32]: i = next(it) 

In [33]: i 
Out[33]: 0 

Вау, мы получили первый элемент из списка! Давайте посмотрим, что произойдет, если мы попробуем поп-элемент с нулевым индексом:

# if i in arr: 
#  print i 
#  arr.pop(0) 

In [34]: i in arr 
Out[34]: True 

In [35]: print i 
0 

In [36]: arr.pop(0) 
Out[36]: 0 

In [37]: arr 
Out[37]: [1, 2, 3, 4, 5, 6, 7, 8, 9] 

Хорошо, элемент выскочил. Переход к следующей итерации цикла:

In [38]: i = next(it) 

In [39]: i 
Out[39]: 2 

Хм ... Похоже, у нас есть второй элемент. Давайте снова выберем первый!

In [40]: i in arr 
Out[40]: True 

In [41]: print i 
2 

In [42]: arr.pop(0) 
Out[42]: 1 

In [43]: arr 
Out[43]: [2, 3, 4, 5, 6, 7, 8, 9] 

Давайте посмотрим на третьей итерации:

In [44]: i = next(it) 

In [45]: i 
Out[45]: 4 

Я думаю, теперь ясно, что цикл будет иметь 5 итераций. На каждой итерации вы удаляете первый элемент. И из-за этого вы будете пропускать нечетные элементы во время итерации.

Смежные вопросы