Функциональное программирование: основы
По сути, функциональное программирование – это стиль программирования, в котором программы пишутся с использованием математических функций, которые принимают неизменные значения в качестве входных данных и создают выходные выражения. Функциональный стиль программирования направлен на то, чтобы избежать побочных эффектов, то есть взаимодействия с внешним миром посредством, скажем, изменения любого состояния или зависимости от него. Эта независимость позволяет очень легко формально проверить «правильность» программы.
В чисто функциональных языках чистые и нечистые части программы хранятся отдельно (например, Haskell). Под «нечистым» я подразумеваю те части программы, которые могут вызывать побочные эффекты.
Python: функциональный стиль
Мы можем писать программы на Python в функциональном стиле. Однако, поскольку этот язык не был специально разработан для функционального программирования, было бы излишне сложно программировать в чисто функциональном стиле.
В этой статье я попытаюсь показать, как программы могут быть написаны на Python в стиле, аналогичном чисто функциональным языкам программирования.
Понимание списка
Хлеб с маслом функционального программирования – список. Мы часто работаем со списками, выбирая элементы из них или выполняя операции над каждым элементом.
Давайте выберем все нечетные числа из списка. В нашем обычном процедурном методе мы бы сделали что-то вроде этого:
#!/usr/bin/env python
def filter_list(li):
spam = []
for i in li:
if i % 2 == 1:
spam.append(i)
return spam
print(filter_list([2, 4, 6, 7, 8, 1, 19, 200, 42, 31]))
Мы можем сделать то же самое с кодом ниже.
li = [2, 4, 6, 7, 8, 1, 19, 200, 42, 31]
nli = [x for x in li if x % 2 == 1]
print(nli)
В обоих случаях вывод выглядит следующим образом.
[7, 1, 19, 31]
Здесь мы выбрали элементы из списка, предоставив условие в форме логической функции.
Второй метод называется списком. Это просто способ создания списков из существующих списков.
Вот где приходят итераторы . Итератор – это объект, возвращаемый повторяемым объектом. Мы вызываем next() для итератора, чтобы получить следующее значение в последовательности, связанной с ним. Любой объект, который реализует метод iter_, называется итеративным. Например, список реализует _iter. Следовательно, он является итеративным и может использоваться в списках.
spam_iterator = iter("foobar")
ns = "".join([c.upper() for c in spam_iterator])
print(ns)
Мы явно получаем «FOOBAR».
Генераторы
Теперь, хотя многие собственные структуры данных Python являются итеративными, существует простой способ генерировать итераторы – функции-генераторы. Заметим:
Приведенный выше код выведет целые числа от 1 до 12.
Мы видим, что функция gen может использоваться для создания итерируемого объекта (генератора).
Альтернативно, генераторы могут быть созданы выражениями генератора, которые являются просто списком, но с заключенными в них скобками, замененными парантезами.
g = (c.upper() for c in "foobar")
Таким образом, с помощью общей концепции итеративности мы можем реализовать некоторые функциональные возможности в Python.
Карта, уменьшение и фильтрация
Отображение , уменьшение и фильтрация являются функциями, которые являются неотъемлемой частью функционального программирования. Эти функции обеспечиваются большинством функциональных языков. Python реализует их по-своему.Карта и фильтр могут рассматриваться как альтернатива спискам.
Карта применяет функцию ко всем членам последовательности (итеративная). Заметим:
def square:
return x*x
foo = map(square, [1, 2, 3])
print(list(foo))
Вывод: [1, 4, 9]
Таким образом, map предоставляет нам возможность применять функцию к каждому члену последовательности, что является повсеместным в функциональном программировании.
Аналогичным образом, фильтр позволяет нам выбирать определенные элементы из последовательности.
def isUpper(c):
return c == c.upper()
a = filter(isUpper, "FreedominObscureandoutlandishcOde")
print(list(a))
Вывод: ['F', 'O', 'O']
В этом случае isUpper является предикатом. Сохраняются только значения, для которых предикат оценивается как true.
Наконец, Reduce позволяет нам накапливать применение функции к нескольким значениям в одно значение. Это также известно как сгиб . Это обеспечивается модулем functools .
from functools import reduce
def add(a, b):
return a + b
print(reduce(add, list(range(1, 6))))
Вывод: 15
Анонимные функции
Мы можем создать безымянные функции (называемые лямбда-функциями) для простоты использования, используя обозначение:
lambda <args> : <expr>
Например, приведенный выше пример фильтра мог быть записан как.
a = list(filter((lambda c: c == c.upper()), "FreedominObscureandoutlandishcOde"))
Мы торгуем читабельностью для простоты использования при использовании лямбда-функций.
Ссылки:
https://wiki.python.org/moin/Generators
Источник записи: https://thedebuggers.com