Функции и замыкание
Долги за прошлую лекцию:
- операция not in 
- Умолчания в секционировании
- Имитация многомерных массивов — список списков - Проблема излишней гибкости: равенство длин строк?
 
- Отсутствие «подковёрного» копирования - например, это совсем не матрица: [[0] * N for i in range(M)] — почему? 
- a.copy(), a[:] и copy.deepcopy() 
 
Функции
Пространства имён: повторение
- Задание функции
- Формальные и фактические параметры, return 
- Duck typing: функция как формализация алгоритма
- вызов функции как локальное пространство имён - globals() и locals() 
- сложный случай определение локальности по связыванию, global 
 
- функция как объект: именование, передача в качестве параметра - работа sort()/sorted() (а заодно и max()/min()) 
 
- Лямбда-функции (функции-выражения)
- Распаковка и запаковка параметров (пока только позиционных) - функция с произвольным числом параметров
 
- Параметры функции по умолчанию (именованные параметры) - (to be continued… они теперь не равны, вообще см. полный вид описания функции) 
 
- Самодокументирование
Про рекурсию
- Рекурсия и цикл. Теория vs. практика. Гвидо, Python и хвостовой вызов - ⇒ максимальная глубина рекурсии
- ⇒ логарифмический критерий уместности рекурсии
 
- Замещение рекурсии стеком. Пример: есть ли среди натуральных чисел Seq такие, что в сумме дают S. Рекурсивный вариант. - S — неизменяемая часть, Seq, Res — изменяемая, значит, их надо сохранять в стек. Рекурсия — это цикл, которые продолжается до тех пор, пока рекурсивные вызовы не кончились.- здесь не тот порядок добавления, для полного соответствия надо в обратном
- вместо списковой сборки надо использовать генератор, но у нас их ещё не было ☺
 
 
Замыкание
- Функция — это объект
- Её можно изготовить внутри другой функции и вернуть
- …причём в зависимости от параметров этой другой функции!
- …в процессе чего некоторые объекты из ПИ создающей функции «залипают» в ПИ создаваемой - только они там навсегда должны залипнуть, а не только на время вызова
- ⇒ .__closure__ 
 
- Это и есть замыкание!
Пример:
и
Also: nonlocal name — явное указание брать имя name из внешнего, но не глобального пространства имён
Модификатор nonlocal для доступа к пространству имён вызывающей функции:
- Без nonlocal имя x оказалось бы локальным 
Замыкание и позднее связывание
Вот этот код не работает так, как может показаться:
Обратите внимание на то, что все 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: MoarTuple 'Подсчёт кратных' Input:- Написать функцию moar(a, b, n) от трёх параметров — целочисленных последовательностей a и b, и натурального числа n. Функция возвращает True, если в a больше чисел, кратных n, чем в b, и False в противном случае. Output:- print(moar((25,0,-115,976,100500,7),(32,5,78,98,10,9,42),5)) - True 
- (задача типа «написать функцию») - EJudge: MaxFun 'Функция побольше' Input:- Написать функцию maxfun(), которая принимает переменное число параметров — числовую последовательность S, функцию F1 и, возможно, ещё несколько функций F2 … Fn. Возвращает она ту из функций Fi, сумма значений которой на всех элементах S наибольшая. Если таких функций больше одной, возвращается Fi с наибольшим i. Output:- from math import * print(maxfun(range(-2,10), sin, cos, exp)(1)) - 2.718281828459045 
- (задача типа «написать функцию») - EJudge: Without2Zeros 'Без двух нулей' Input:- Написать функцию No_2Zero(N, K), которая вычисляет количество N-значных чисел в системе счисления с основанием K, таких что их запись не содержит двух подряд идущих нулей. Лидирующие нули не допускаются. Для EJudge N⩽33. Output:- print(No_2Zero(6, 3)) - 328 
- (задача типа «написать функцию») - EJudge: ArithFunct 'Арифметика функций' Input:- Написать четыре функции (функционала): ADD(f, g), SUB(f, g), MUL(f, g) и DIV(f, g), параметрами которых могут быть как обычные объекты, так и функции от одной переменной (проверить, является ли объект функцией можно с помощью callable(объект)). Возвращать эти функционалы должны функцию от одной переменной h(x), которая выполняет соответствующее действие — f(x)+g(x), f(x)-g(x), f(x)*g(x) или f(x)/g(x) — над этими переменными. Если f или g не были функцией, вместо f(x) используется f, а вместо g(x) — g (например, при умножении функции на константу). Output:- from math import * f = SUB(sin, cos) print(f(12), sin(12)-cos(12)) g = DIV(sin, cos) print(g(pi/6), tan(pi/6)) h = MUL(exp, 0.1) print(h(2), e**2/10) t = ADD(len, sum) print(t(range(5))) - -1.380426876732927 -1.380426876732927 0.5773502691896256 0.5773502691896257 0.7389056098930651 0.738905609893065 15 
