Рекурсия и итераторы
Долги за прошлый раз
Ещё раз про eval(input())
Ещё раз про операцию () + про callable() и __call__()
Про рекурсию
Рекурсия и цикл. Теория vs. практика. Гвидо, Python и хвостовой вызов
- ⇒ максимальная глубина рекурсии
- ⇒ логарифмический критерий уместности рекурсии
Замещение рекурсии стеком. Пример: есть ли среди натуральных чисел Seq такие, что в сумме дают S. Рекурсивный вариант.
- S — неизменяемая часть, Seq, Res — изменяемая, значит, их надо сохранять в стек. Рекурсия — это цикл, которые продолжается до тех пор, пока рекурсивные вызовы не кончились. (здесь не тот порядок добавления, для полного соответствия надо в обратном)
Про генераторы
Вычислимые последовательности.
Как задать самому? Например, циклической сборкой, см. пример выше
iterator object, next(), StopIteration
протокол последовательности: методы .__getitem__() или .__iter__()
iter() от всего подряд
⇒ работа цикла for: сделать итератор и по нему ходить
Создание и использование генератора, (yield ⇒ функция, возвращающая генератор, а уж генератор yield-ит результаты)
Пример работы, return в генераторе
- Генератор — «одноразовая» последовательность
yield from, важность этой конструкции
Itertools (сколько успеем)
Бесконечные последовательности и частичные вычисления, itertools
- Обработка вычислимых последовательностей
- функциональное программирование
- Обзор
- Бесконечные последовательности
- Модификация последовательностей
- Комбинаторика
Д/З
TODO
Прочитать что Гвидо думает о хвостовых рекурсивных вызовах, про итераторы и генераторы, про yield from и про itertools
- (это не рекурсия, а вот итератор применить можно ☺)
EJudge: UniInterval 'Объединение отрезков'
Вводится кортеж пар натуральных чисел. Это координаты отрезков на прямой. Рассмотрим объединение этих отрезков и найдём длину этого объединения (т. е. совокупную длину всех «закрашенных» нашими отрезками отрезков на прямой).
(66, 91), (152, 230), (21, 81), (323, 342), (158, 211), (286, 332), (294, 330), (18, 58), (183, 236)
213
EJudge: BinPow 'Бинарное возведение в степень'
Написать рекурсивную функцию BinPow(), которая принимает три параметра: python3-объект a, натуральное число 0<N<1000000, и некоторую ассоциативную бинарную функциюf(). Функция BinPow() реализует алгоритм бинарного возведения в степень (кроме нулевой степени). Результатом BinPow(a, n, f) будет применение f(x) к a n-1 раз. Более точно, BinPow(a, 1, f) == a, BinPow(a, 2, f) == f(a,a), BinPow(a, 3, f) == f(a,f(a, a)) == f(f(a, a), a) (в силу ассоциативности), … BinPow(a, n, f) == f(f(…f(a, a), …), a).
print(BinPow(2,33,int.__mul__), 2**33) print(BinPow("Se", 7, str.__add__))
8589934592 8589934592 SeSeSeSeSeSeSe
EJudge: IterPi 'Пи /кродёться/'
Пользуясь формулой Лейбница для вычисления числа Пи:
написать бесконечный генератор pigen(), возвращающий последовательно 4, 4-4/3, 4-4/3+4/5, 4-4/3+4/5-4/7…;
P=pigen() print(next(P), next(P), next(P), next(P), sep="\n")
4.0 2.666666666666667 3.466666666666667 2.8952380952380956
EJudge: ChainSlice 'Режем лазанью'
Написать функцию chainslice(begin, end, seq0, seq1, …), которая принимает не менее трёх параметров: два целых числа и не менее одной последовательности. Рассмотрим последовательность seq, образованную всеми элементами seq0, затем — всеми элементами seq1, и т. д. Вернуть эта функция должна итератор, пробегающий элементы последовательности seq с №begin до №end-1 включительно.
print(*(chainslice(17, 33, range(7), range(8), range(6), range(9), range(5))))
2 3 4 5 0 1 2 3 4 5 6 7 8 0 1 2
Д/З мне:
I = iter(Seq) old = next(I) for new in I: ...
вместо