2013-06-04 2 views
0

У меня есть список из четырех цифр:Неожиданное поведение в зацикливание список

mylist=[3,5,67,4] 

Я хочу, чтобы удалить все нечетные числа. Итак, я написал следующее:

for item in mylist: 
    if item%2==1: 
    mylist.remove(item) 

Когда я печатаю mylist, я получаю следующее:

[5,4] 

Я не могу понять, почему это происходит. Тем не менее, когда я добавляю оператор печати после if заявления я получить правильный ответ:

for item in mylist: 
    if item%2==1: 
    mylist.remove(item) 
    print mylist 

что дает:

[4] 

Что здесь происходит? Что мне не хватает?

+0

Это распространенная ошибка, которая происходит, когда вы мутируете последовательность, итерации по ней. – mgilson

+0

Конечно. Я не знаю, почему я этого не видел. Я получаю это сейчас. Кроме того, я согласен с тем, что это дублирующий вопрос и отметил его как таковой. – Fezter

ответ

5

Это плохая идея, чтобы изменить список на месте в то время как итерация его. По мере того, как список изменяется, пока вы перебираете его, ваша итерация продолжается, как если бы список был неизменным - создавая странные результаты.

Лучшее решение построить новый список - оптимально с list comprehension вместо:

mylist = [item for item in mylist if item % 2 == 0] 

Если вы должны изменить список, вы можете присвоить значения обратно после (mylist[:] = ...), но вряд ли вы требуется, чтобы изменить его на месте.

Это также имеет то преимущество, что оно читаемо и кратким.

+0

более надежным решением будет 'mylist [:] = mylist [:: 2]'. В противном случае, в другой ситуации, он может добавить случайную локальную привязку. – Elazar

+1

@ Elazar: Это не решает исходную проблему, которая заключается в удалении всех нечетных чисел. Это просто возвращает список, содержащий все остальные элементы из исходного списка. –

+0

@Elazar Это не решает проблему, и в большинстве случаев нет необходимости фактически изменять существующий список, как я сказал в ответе. –

3

Вам необходимо перебрать копию списка. Изменение списка непосредственно в цикле - вот что вызывает проблему, с которой вы столкнулись. Вот предпочтительный способ сделать это:

for item in mylist[:]: 
    if item%2==1: 
     mylist.remove(item) 
0

Я согласен с другими ответами, которые говорят, что небезопасно перебирать список и изменять этот список в цикле. Одно из решений, которое я нашел для таких проблем - особенно удаление из списка, - это цикл назад с использованием индекса , а не итератора.

Мой питон код ржавый, так что я буду использовать C-подобный псевдокод вместо ...

for (i = lastindex; i >= 0; --i) 
    if (some condition involving list[i]) 
    remove item at index i 

Это работает при удалении из списка, так как элементы, сдвинутые удалением являются те, которые вы уже посмотрел на; ваш индекс i по-прежнему действует, как и все предметы, которые вы еще не оценили!

+0

Цитирование по индексу не является Pythonic - оно негибким (не работает на итераторах, просто последовательно), его труднее читать, и он медленный. –

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