Функции и замыкание
sorted() и max()/min() там, где функции
Функции
Пространства имён: повторение
- лямбда-функции (функции-выражения)
Задание функции: формальные и фактические параметры, return
- Duck typing: функция как формализация алгоритма
вызов функции как локальное пространство имён
globals() и locals()
сложный случай определение локальности по связыванию, global
nonlocal для вложенных вызовов
- функция как объект: именование, передача в качестве параметра
- Распаковка и запаковка параметров
- функция с произвольным числом параметров
- Параметры функции по умолчанию (именованные параметры)
(to be continued… они теперь не равны, вообще см. полный вид описания функции)
Про рекурсию
Рекурсия и цикл. Теория vs. практика. Гвидо, Python и хвостовой вызов
- ⇒ максимальная глубина рекурсии
- ⇒ логарифмический критерий уместности рекурсии
Замещение рекурсии стеком. Пример: есть ли среди натуральных чисел Seq такие, что в сумме дают S. Рекурсивный вариант.
- S — неизменяемая часть, Seq, Res — изменяемая, значит, их надо сохранять в стек. Рекурсия — это цикл, которые продолжается до тех пор, пока рекурсивные вызовы не кончились.
- здесь не тот порядок добавления, для полного соответствия надо в обратном
- вместо списковой сборки надо использовать генератор, но у нас их ещё не было ☺
Замыкание
- Функция — это объект
- Её можно изготовить внутри другой функции и вернуть
- …причём в зависимости от параметров этой другой функции!
- …в процессе чего некоторые объекты из ПИ создающей функции «залипают» в ПИ создаваемой
- только они там навсегда должны залипнуть, а не только на время вызова
⇒ .__closure__
- Это и есть замыкание!
Пример:
и
Also: nonlocal name — явное указание брать имя name из внешнего, но не глобального пространства имён
Замыкание и позднее связывание
Вот этот код не работает так, как может показаться:
Обратите внимание на то, что все adder-ы работают одинаково!. Поскольку i для сгенерированных функций нелокальное, оно попадает в замыкание, и это один и тот же объект во всех adder-ах:
>>> c = create_adders() >>> c[1] <function create_adders.<locals>.adder at 0x7f272d2f93b0> >>> c[1].__closure__ (<cell at 0x7f272d1c1510: int object at 0x7f272db36660>,) >>> c[2].__closure__ (<cell at 0x7f272d1c1510: int object at 0x7f272db36660>,) >>> c[2].__closure__[0].cell_contents 9 >>> c[1].__closure__[0].cell_contents 9
Если мы хотели не этого, надо сделать так, чтобы при создании очередного adder-а его i именовало новый объект:
При этом никакого замыкания не произойдёт, у каждого adder-а будет своё локальное j, инициализированное соответствующим значением i. (Если бы нам нужно было сильнее запутаться, мы могли бы написать i=i вместо j=i ☺ ).
Д/З
- Прочитать:
в Tutorial про функции
Про замыкания: Gabor Laszlo Hajba и Dmitry Soshnikov
Посмотреть, как оформлять задачи типа «написать функцию», Три задачи этого Д/З имеют такой новый тип.
EJudge: DivDigit 'Цифроделители'
Написать функцию divdigit(N), которой передаётся произвольное натуральное число N, а в ответ функция возвращает количество цифр этого числа, являющихся её делителями.
print(divdigit(312345))
4
EJudge: BinPow 'Бинарное возведение в степень'
Написать функцию BinPow(), которая принимает три параметра: python3-объект a, натуральное число 0<N<1000000, и некоторую ассоциативную бинарную функцию f(). Функция BinPow() реализует алгоритм бинарного возведения в степень (кроме нулевой степени). Результатом BinPow(a, n, f) будет применение f(x) к a n-1 раз.
8589934592 8589934592 SeSeSeSeSeSeSe
EJudge: Det4x4 'Определитель матрицы 4×4'
Матрица 4×4 задаётся кортежем из 4 кортежей по 4 целых числа в каждом. Посчитать точный определитель этой матрицы. Пользоваться itertools нельзя.
(5, -4, 4, -7), (1, -2, 6, 0), (3, -8, -6, -4), (-1, 2, -9, 3)
702
EJudge: FunVect 'Вектор функций'
Написать функцию superposition(funmod, funseq), которая принимает два параметра — функцию funmod() от одного переменного, и последовательность funseq[] функций от одного переменного. superposition() возвращает также список функций funres[], каждая из которых представляет собой суперпозицию вида funres[i] ::== funmod(funseq[i])
0.8414709848078965 0.5403023058681398 0.9092974268256817 0.4161468365471424