Sobes.tech
Junior — Senior
47

Особенности работы filter и одноразовых итераторов

Условие задачи

Разобрать, почему данная программа выводит именно такой результат и какие особенности поведения filter и итераторов приводят к этому.

seq = [1, 2, 3, 4, 5]

# Получаем итератор нечётных чисел из seq
odd_iter = filter(lambda x: x % 2, seq)

if any(odd_iter):
    print("Has odds:")
    for odd in odd_iter:
        print(odd)

print(any(odd_iter))

Вывод программы:

Has odds:
3
5
False

Что происходит:

  1. filter возвращает итератор, а не список. Его элементы вычисляются «на лету» и могут быть получены только один раз.
  2. В условии if any(odd_iter): функция any последовательно перебирает элементы итератора, пока не встретит истинный (True). При этом первые два нечётных числа — 1 и 3 — проверяются, и как только найдено 3 (истинное значение), перебор останавливается. Итератор уже «прокручён» до элемента 5.
  3. После выполнения any итератор находится в состоянии «потраченной» части: уже прошедшие элементы недоступны. Поэтому в последующем for odd in odd_iter: остаётся только один элемент — 5, который и выводится.
  4. Последний вызов any(odd_iter) снова пытается пройтись по оставшимся элементам. Так как после вывода 5 в итераторе ничего не осталось, any сразу возвращает False.

Итого, filter создаёт одноразовый итератор, а любые функции, которые его потребляют (any, list, цикл for и т.п.), «истощают» его, делая последующие попытки получить данные пустыми.