Неожиданное поведение итератора python при изменении его списка внутри цикла for-in

Главное правило: не изменяйте список во время итерации по нему, но ...

Учитывая следующий код для удаления определенного элемента из списка Python (но намеренно написанного в виде цикла):

mylist = ['a', 'b', 'c', 'd', 'e', 'f']

for i in mylist:
    if i == 'c':
        mylist.remove(i)

print(mylist)

>> ['a', 'b', 'd', 'e', 'f']

Каким образом итератор не теряется во время итерации, если список изменяется внутри цикла? Я ожидал, что это приведет к ошибке или непоследовательному поведению.

0
0
28
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Итераторы списков (другие итераторы могут вести себя по-другому) работают, запоминая, какой индекс они в настоящее время находятся, и когда вы вызываете следующий, он проверяет, находится ли индекс в диапазоне, и если да, получает элемент и затем обновляет индекс. Ваш код достигает индекса 2, удаляет 'c', затем переходит к индексу 3, который теперь является записью 'e', и продолжается, полностью пропуская запись 'd'. Если вы добавите оператор печати в цикл for, вы увидите поведение.

Вы можете посмотреть исходный код C для объектов списка по адресу:

https://github.com/python/cpython/blob/master/Objects/listobject.c

Найдите «listiter_next», чтобы увидеть реализацию.

Он проверяет, меньше ли текущий индекс, чем длина списка:

if (it->it_index < PyList_GET_SIZE(seq))

и если это так, получает элемент и увеличивает индекс:

item = PyList_GET_ITEM(seq, it->it_index);
++it->it_index;

Другие вопросы по теме