Неожиданное поведение итератора Python при изменении его списка внутри цикла for-in - PullRequest
0 голосов
/ 31 октября 2018

Основное правило: не изменяйте список во время его перебора, но ...

С учетом следующего кода для удаления определенного элемента из списка 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']

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

1 Ответ

0 голосов
/ 31 октября 2018

Итераторы списка (другие итераторы могут вести себя по-разному) работают, запоминая, к какому индексу они относятся в данный момент, и при следующем вызове проверяют, находится ли индекс в диапазоне, и если да, получают элемент, а затем обновляют индекс , Ваш код достигает индекса 2, удаляет 'c', затем переходит к индексу 3, который теперь является записью 'e' и продолжается, пропуская запись 'd' полностью. Если вы добавите оператор print в цикл 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...