Функции и функциональное программирование
Функция – фрагмент кода, который можно вызывать из любого места программы. Например, с помощью функции len() можно получать количество элементов последовательности. Функции позволяют уменьшить избыточность программного кода и повысить его структурированность.
Создание функции и ее вызов Функция описывается с помощью ключевого слова def: def ([Параметры]): [" " " Строка документирования " " "] [return ] Имя функции должно быть уникальным идентификатором, состоящим из латинских букв, цифр и знаков подчеркивания, причем имя функции не может начинаться с цифры В качестве имени нельзя использовать ключевые слова; кроме того, следует избегать совпадений с названиями встроенных идентификаторов Регистр символов в названии имеет значение!
Если тело функции не содержит выражений, то внутри необходимо разместить оператор pass. Этот оператор удобно использовать на этапе отладки программы, когда мы определили функцию, а тело будем дописывать позже: def f_pass(): #данная программа pass ничего не делает return(необязательная) позволяет вернуть значение из функции. После использования этой инструкции выполнение функции будет остановлено: def f_test(): print "Текст до инструкции return " return "Возвращаемое значение " print «Это выражение никогда не будет выполнено " print f_test() # Вызываем функцию Инструкции return может не быть вообще, тогда выполняются выражения внутри функции и возвращается значение None
Определение функций: def f_print_ok(): """ Пример функции без параметров """ print """Сообщение при удачно выполненной операции" def f_print(m): """ Пример функции с параметром """ print m def f_sum(x, y): """ Пример функции с параметрами, возвращающей сумму двух переменных """ return x + y Вызов функций: f_print_ok() # Вызываем функцию без параметров f_print("Сообщение") # Функция выведет сообщение v1 = f_sum(5, 2) # Переменной v1 будет присвоено значение 7 a, b = 10, 50 v2 = f_sum(a, b) # Переменной v2 будет присвоено значение 60 Как видно из примера, имя переменной в вызове функции может не совпадать с именем переменной в определении функции. Количество же параметров в определении функции должно совпадать с количеством параметров при вызове! Оператор +, используемый в f_sum(), применяется не только для сложения, но и позволяет объединить последовательности.
Расположение определений функций С помощью оператора ветвления if можно изменить порядок выполнения программы. Таким образом, можно разместить внутри условия несколько определений функций с одинаковым названием, но разной реализацией. все выражения в программе выполняются последовательно сверху вниз, это означает, что прежде чем использовать идентификатор, его необходимо предварительно объявить, присвоив ему значение. Поэтому определение функции должно быть расположено перед вызовом функции. Правильно: def f_sum(x, y): return x + y v = f_sum(10, 20) # Вызываем после определения, все нормально Неправильно: v = f_sum(10, 20) # Идентификатор еще не def f_sum(x, y): определен, это ошибка return x + y
Необязательные параметры Чтобы сделать некоторые параметры необязательными, нужно в определении функции присвоить этому параметру начальное значение. def f_sum(x, y=2): # y - необязательный параметр return x + y v1 = f_sum(5) # Переменной v1 будет присвоено значение 7 v2 = f_sum(10, 50) # Переменной v2 будет присвоено значение 60 таким образом, если второй параметр не задан, то его значение будет 2 необязательные параметры, должны следовать после обязательных, иначе выведется отчет об ошибке
Сопоставление по ключам Можно передавать значение в функцию, используя сопоставление по ключам – для этого при вызове функции параметрам присваиваются значения Последовательность указания параметров произвольная def f_sum(x, y): return x + y print f_sum(y=20, x=10) #Сопоставление по ключам Сопоставление по ключам очень удобно использовать, если в функции несколько необязательных параметров, тогда не нужно перечислять все значения, а достаточно присвоить значение нужному параметру: def f_sum(a=2, b=3, c=4): # Все параметры необязательны return a + b + c print f_sum(2, 3, 20) # Позиционное присваивание print f_sum(c=20) # Сопоставление по ключам
Передача значений из кортежа и списка если значения параметров, которые планируется передать в функцию, содержатся в кортеже, то перед объектом следует указать символ *: def f_sum(a, b, c): return a + b + c t1, arr = (1, 2, 3), [1, 2, 3] print f_sum(*t1) # Распаковываем кортеж print f_sum(*arr) # Распаковываем список t2 = (2, 3) print f_sum(1, *t2) # Можно комбинировать значения
Передачи значений из словаря если значения параметров содержатся в словаре, то распаковывать словарь можно, указав перед ним две звездочки **: def f_sum(a, b, c): return a + b + c d1, {"a": 1, "b": 2, "c": 3} print f_sum(**d1) # Распаковываем словарь t, d2 = (1, 2), {"с": 3} print f_sum(*t, **d2) # Можно комбинировать значения Распаковать кортежи, списки и словари позволяет также функция apply()(устаревшая функция) apply( [, [, ]])
Переменное число параметров в функции если перед параметром в определении функции указать *,то функции можно будет передать произвольное количество параметров. Все переданные параметры сохраняются в кортеже; Суммирование произвольного количества чисел: def f_sum(*t): """Функция принимает произвольное кол-во параметров""" res = 0 for i in t # Перебираем кортеж с переданными параметрами res += i return res print f_sum(10, 20) # Выведет: 30 print f_sum(10, 20, 30, 40, 50, 60) # Выведет 210
Анонимные функции – у них нет имени! то есть лямбда-функции, описывается с помощью ключевого слова lambda: lambda [ [, …, ]]: в качестве значения лямбда- функция возвращает ссылку на объект-функцию, которую можно сохранить в переменной или передать в качестве параметра в другую функцию вызывать как обычную, с помощью круглых скобок, внутри которых передаваемые параметры также могут быть необязательные параметры f1 = lambda: # Функция без параметров f2 = lambda x, y: x + y # Функция с 2 параметрами f3 = lambda x, y, z: x + y + z # с 3 print f1() # Выведет: 30 print f2(5, 10) # Выведет : 15 print f3(5, 10, 30) # Выведет: 45
Функции-генераторы функция-генератор – функция, которая может возвращать одно значение из нескольких значений на каждой итерации приостановить выполнение и превратить функцию в генератор позволяет ключевое слово yield Функция, которая возводит элементы последовательности в указанную степень: def f_test(x, y): for i in xrange(1, x + 1): yield i ** y for n in f_test(10, 2): print n, # Выведет: print # Вставляем пустую строку for n in f_test(10, 3): print n, # Выведет:
Декораторы функций декораторы позволяют изменить поведение обычных функций, например, выполнить какие то действия перед выполнением функции: def f_deco(f): # Функция-декоратор print "f_test(f)" return f # Возвращаем ссылку на def f_test(x) : return "x = %s" % x print f_test(10) перед определением функции f_test указывается название функции f_deco с Таким образом f_deco становится декоратором функции f_test; в качестве параметра функция- декоратор принимает ссылку на функцию, поведение которой нужно изменить, и должна возвращать ссылку на ту же функцию или какую – любо другую Выведет: Вызвана функция f_test() х = 10
Рекурсия, вычисление факториала Рекурсия – возможность функции вызывать саму себя. Её удобно использовать для перебора объекта, имеющего заранее неизвестную структуру, или выполнения неопределенного количества операций # -*- coding: ср1251 -*- def factorial(n): if == 0 or n == 1: return 1 else: return n * factorial(n - 1) while True: x = raw_input("Введите число: ") if x.isdigit(): # Если строка содержит только цифры x = int(x) # Преобразуем строку в число break # Выходим из цикла else: print "Вы ввели не число" print "Факториал числа %s = %s" % (x, factorial(x))
Глобальные и локальные переменные Глобальные переменные – переменные, объявленные в программе вне функции def f_test(glob2): print " Значение глобальной переменной glob1 = %s" % glob1 glob2 += 10 print " Значение локальной переменной glob2 = %s" % glob 2 glob1, glob2 = 10, 5 f_test(77) # Вызываем функцию print " Значение глобальной переменной glob2 = %s" % glob2 Переменной glob2 внутри функции присваивается значение параметра, поэтому создается новое имя glob2, которое является локальным, все изменения внутри функции не затронут значение одноименной глобальной переменной. Локальные переменные – те, которым внутри функции присваивается значение. Если имя локальной совпадает с глобальной, то все операции внутри функции осуществляются с локальной переменной, а значение глобальной не изменяется. Локальные переменные видны только внутри тела функции. Результат выполнения: Значение глобальной переменной glob1 = 10 Значение глобальной переменной glob2 = 87 Значение глобальной переменной glob2 = 5
Функциональное программирование – раздел дискретной математики, в которой процесс вычисления трактуется как вычисление значений функций в математическом понимании ФункциональноеИмперативное вычисление результатов функций от исходных данных и результатов других функций выходные данные зависят только от входных предполагает явное хранение состояния программы Опираются на аргументы, состояние внешних переменных, могут иметь побочные эффекты Функции высших порядков – которые в качестве аргументов могут принимать функции, и возвращать другие функции. Позволяют использовать карринг - преобразование функции от пары аргументов в функцию, берущую свои аргументы по одном
Чистые функции не имеют побочных эффектов ввода- вывода и памяти: удаление без вреда результата, если он не используется принцип прозрачности ссылок удовлетворяет принципам thread-safe свобода компилятору комбинировать и реорганизовывать вычисление Рекурсивные функции - вызывают сами себя, позволяя операции выполняться снова и снова Главная особенность: реализация модели вычислений без состояния(+,-)
Стили программирования Императивные программы имеют склонность акцентировать последовательности шагов для выполнения какого-то действия, а функциональные программы к расположению и композиции функций, часто не обозначая точной последовательности шагов: # imperative style target = [] # create empty list for item in source_list: # iterate over each thing in source trans1 = G(item) # transform the item with the G() function trans2 = F(trans1) # second transform with the F() function target.append(trans2) # add transformed item to target # functional style # FP-oriented languages often have standard compose() compose2 = lambda A, B: lambda x: A(B(x)) target = map(compose2(F, G), source_list) Императивная версия Функциональная версия
предпосылки для полноценного функционального программирования в Python: функции высших порядков обработка списков рекурсия определяется с помощью оператора def или лямбда- выражением: def func(x, y): return x**2 + y**2 эквивалентны func = lambda x, y: x**2 + y**2 формальные и фактические аргументы, при вызове фактические: func(2, y=7) позиционные аргументы именованные повторы в именах аргументов недопустимы!
Списочные выражения - наиболее выразительное из функциональных средств Питона. вычисление списка квадратов натуральных чисел,
Встроенные функции высших порядков map() позволяет обрабатывать одну или несколько последовательностей с помощью заданной функции: >>> list1 = [7, 2, 3, 10, 12] >>> list2 = [-1, 1, -5, 4, 6] >>> map(lambda x, y: x*y, list1, list2) [-7, 2, -15, 40, 72] аналогичного (только при одинаковой длине списков) результата можно добиться с помощью списочных выражений: >>> [x*y for x, y in zip(list1, list2)] [-7, 2, -15, 40, 72]
filter() фильтрует значения последовательности, в результирующем списке только те значения, для которых значение функции для элемента истинно: >>> spisok = [10, 4, 2, -1, 6] >>> filter(lambda x: x < 5, spisok) # В результат попадают только те эл-ты x, для которых x < 5 истинно [4, 2, -1] то же самое с помощью списковых выражений: >>> spisok = [10, 4, 2, -1, 6] >>> [x for x in spisok if x < 5] [4, 2, -1]
reduce() – организация цепочечных вычислений в списке произведение элементов : >>> spisok = [2, 3, 4, 5, 6] >>> reduce(lambda res, x: res*x, spisok, 1) 720 Вычисления происходят в следующем порядке: ((((1*2)*3)*4)*5)*6 Цепочка вызовов связывается с помощью промежуточного результата (res) Если список пустой, просто используется третий параметр (в случае произведения нуля множителей это 1): >>> reduce(lambda res, x: res*x, [], 1) 1 промежуточный результат необязательно число, это может быть любой другой тип данных, в том числе и список.
apply() применения другой функции к позиционным и именованным аргументам, заданным списком и словарем: >>> def f(x, y, z, a=None, b=None):... print x, y, z, a, b... >>> apply(f, [1, 2, 3], {'a': 4, 'b': 5})
Замыкания – функции, определяемые внутри других функций def multiplier(n): "multiplier(n) возвращает функцию, умножающую на n" def mul(k): return n*k return mul # того же эффекта можно добиться выражением # multiplier = lambda n: lambda k: n*k mul2 = multiplier(2) # mul2 - функция, умножающая на 2, например, mul2(5) == 10
Итераторы Применение перечисляющего сортирующего итераторов: >>> it = enumerate(sorted("PYTHON")) # итератор для перечисленных отсортированных букв слова >>> it.next() # следующее значение (0, 'H') >>> print list(it) # оставшиеся значения в виде списка [(1, 'N'), (2, 'O'), (3, 'P'), (4, 'T'), (5, 'Y')] Использование модуля itertools: >>> from itertools import chain >>> print list(chain(iter("ABC"), iter("DEF"))) ['A', 'B', 'C', 'D', 'E', 'F']
Ленивые выражения простейшие логические операции or и and не вычисляют второй операнд, если результат определяется первым операндом лямбда-выражения определенные пользователем классы с ленивой логикой вычислений >>> def f():... print "f"... return "f"... >>> def g():... print "g"... return g"... >>> f() if True else g() f 'f'' >>> f() if False else g() g 'g'
Конец=)