Для цикла повторяется меньше раз, чем я ожидал в Python - PullRequest
4 голосов
/ 31 мая 2019

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

a = [1, 2, 3, 4, 5, 6]
for elem in a:
        del a[0]
        print(a)

Ответы [ 3 ]

4 голосов
/ 31 мая 2019

Вы удаляете первый элемент в каждой итерации цикла на del a[0], поэтому итератор очищается за 3 шага, потому что он перемещается к элементу после того, который вы удалили на следующей итерации. Вы можете проверить элемент, в котором в данный момент находится итератор, и статус списка в коде ниже

a = [1, 2, 3, 4, 5, 6]
for elem in a:
    print(elem)
    del a[0]
    print(a)

Выход

1
[2, 3, 4, 5, 6]
3
[3, 4, 5, 6]
5
[4, 5, 6]

Вы можете рассматривать его как указатель, указывающий на первый элемент списка, этот указатель перескакивает на 2 шага, когда вы удаляете первый элемент на каждой итерации, и может перемещаться только 3 раза для 6 элементов.

Обычно плохая идея изменять тот же список, который вы повторяете. Но если вы действительно хотите, вы можете перебрать копию списка a[:], если вы действительно хотите удалить элементы

a = [1, 2, 3, 4, 5, 6]
for elem in a[:]:
    del a[0]
    print(a)

Выход

[2, 3, 4, 5, 6]
[3, 4, 5, 6]
[4, 5, 6]
[5, 6]
[6]
[]
2 голосов
/ 31 мая 2019

Итератор list в CPython работает путем итерации по позициям списка.Вы можете думать, что это работает так:

def list_iter(items: list):
    index = 0
    while True:
        yield items[index]
        index += 1

Другими словами, итерация предоставляет элемент в 0, затем 1, затем 2 и так далее.Предварительная выборка элементов не производится - при необходимости элемент ищется из списка.

При удалении первого элемента на каждом шаге список сокращается на 1 на каждом шаге.Поскольку вы начинаете со списка из 6 элементов, на третьей итерации он сокращается до 3 элементов - это означает, что четвертая итерация не может найти элемент.Таким образом, ваша итерация заканчивается после трех шагов.

Это можно увидеть при печати также текущего элемента в каждом цикле.Чтобы визуализировать эффект, используйте enumerate, чтобы получить индекс итерации.Обратите внимание, что он увеличивается на один индекс, но значения также сдвигаются для общего смещения двух:

>>> a = [1, 2, 3, 4, 5, 6]
... for idx, elem in enumerate(a):
...     print(elem, 'from', a)
...     print('      ', '   '*idx, '^')
...     del a[0]
...
1 from [1, 2, 3, 4, 5, 6]
        ^
3 from [2, 3, 4, 5, 6]
           ^
5 from [3, 4, 5, 6]
              ^

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

a = [1, 2, 3, 4, 5, 6]
for elem in a.copy():
    del a[0]
    print(a)
1 голос
/ 31 мая 2019

Итерировать по и , удаляя элементы из списка одновременно, довольно сложно.Один из способов справиться с этим - просмотреть список в обратном порядке:

a = [1, 2, 3, 4, 5, 6]
for elem in reversed(a):
    print(a)
    del a[0]
print(a)

. Будет выведено:

[1, 2, 3, 4, 5, 6]
[2, 3, 4, 5, 6]
[3, 4, 5, 6]
[4, 5, 6]
[5, 6]
[6]
[]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...