Итераторы

Итераторы вокруг нас

Вычислимые последовательности, например, range().

Протокол итерируемой последовательности:

Собственно итераторы:

Как сделать итератор:

  1. iter(итерируемый_объект): У объекта есть метод .__iter__()

  2. или iter(индексируемый_объект): У объекта есть метод .__getitem__(int) (индексация пойдёт с нуля)

    • Вместо StopIteration используется IndexError

  3. или iter(функция, стоп-значение) — возвращает результат функции, пока он не равен стоп-значению

       1 >>> import random
       2 >>> d = iter(lambda: random.randrange(10), 7)
       3 >>> list(d)
       4 [3, 1, 9, 6, 4, 5, 3, 9, 9, 2, 4, 2, 0, 0, 0, 3, 4, 1]
       5 
    

Использование итераторов в протоколах:

Генераторы

Как задать самому?

Генератор-функция

ИРЛ: итераторы — это вычислимые последовательности, в т. ч. бесконечные

Параметрические генераторы

В генератор можно затолкать значение на каждом обороте (оно прочтётся yield-ом).

   1 >>> def stopicot(base):
   2   2     what = yield base
   3   3     while what:
   4   4         what += yield base + what
   5 >>> sto = stopicot(100500)
   6 >>> next(sto) # или, что то же самое, sto.send(None)
   7 100500
   8 >>> sto.send(1)
   9 100501
  10 >>> sto.send(1)
  11 100502
  12 >>> sto.send(-1)
  13 100501
  14 >>> sto.send(-1)
  15 Traceback (most recent call last):
  16   File "<stdin>", line 1, in <module>
  17 StopIteration

Зачем это может быть нужно?

Itertools (сколько успеем)

Обработка вычислимых последовательностей и функциональное программирование

Обзор itertools:

Частичное вычисление (в т. ч. бесконечных последовательностей)

Д/З

  1. Прочитать
  2. EJudge: LookSay 'Прочти это вслух'

    Написать генератор-функцию LookSay() цифр последовательности Конвея «Look and Say». Сама последовательность должна быть целочисленной. Описание в Википедии

    Input:

       1 for i, l in enumerate(LookSay()):
       2     print(f"{i}: {l}")
       3     if i > 10:
       4         break
    
    Output:

    0: 1
    1: 1
    2: 1
    3: 2
    4: 1
    5: 1
    6: 2
    7: 1
    8: 1
    9: 1
    10: 1
    11: 1
  3. EJudge: ManyFor 'Многоцикл'

    Написать генератор-функцию manyfor(order, *sequences), у которой только один обязательный параметр — последовательность индексов, остальные — произвольные итерируемые последовательности. Функция должна возвращать генератор, который поочерёдно перебирает элементы последовательностей в порядке, заданном order. Если соответствующая значению из order последовательность опустела или это значение не является индексом sequences, генератор заканчивает работу.

    • {i} Последовательности могут тоже быть генераторами, причём и бесконечными в том числе

    Input:

       1 print("".join(manyfor((1, 0, 2) * 16, "ae kha-kha", "Mnsatm", "nrme noob")))
    
    Output:

    Manners maketh man
  4. EJudge: IterCalc 'Калькулятератор'

    Написать генератор-функцию itercalc(), которая возвращает параметрический итератор, работающий как примитивный стековый калькулятор. Команды калькулятору посылаются с помощью .send(), возвращаемое значение — None, за исключением команды «?», которая возвращает вершину стека. Другие команды — это либо целое число (оно добавляется на стек), либо одна из операций «+», «-», «*» или «/», которые заменяют два верхних элемента стека на результат применения к ним соответствующей операции (вершина стека — это второй операнд). Деление целочисленное. Если операция невозможна, она не выполняется, и выводится ошибка:

    • Zero division при попытке поделить на 0

    • Insufficient stack, когда нужного элемента на стеке нет

    • Unknown command, если команда не распознана

    Input:

       1 calc = itercalc()
       2 next(calc)
       3 for cmd in "? 3 -2 - what 5 * 2 / ?".split():
       4     if (res := calc.send(cmd)) is not None:
       5         print(res)
    
    Output:

    Insufficient stack
    Unknown command
    12
  5. TODO ещё одну на itertools

LecturesCMC/PythonIntro2025/07_Iterators (последним исправлял пользователь FrBrGeorge 2025-10-20 14:45:20)