Python/Функциональное программирование на Python: различия между версиями

Содержимое удалено Содержимое добавлено
оформление ВУ
м <source> -> <syntaxhighlight> (phab:T237267)
 
Строка 6:
Функция в Python может быть определена с помощью оператора <code>def</code> или [[w:Лямбда-выражения|лямбда-выражением]]. Следующие операторы эквивалентны:
 
<sourcesyntaxhighlight lang="python">
def func(x, y):
return x**2 + y**2
 
func = lambda x, y: x**2 + y**2
</syntaxhighlight>
</source>
 
В определении функции фигурируют [[w:Формальный аргумент|формальные аргументы]]. Некоторые из них могут иметь значения по умолчанию. Все аргументы со значениями по умолчанию следуют после аргументов без значений [[w:по умолчанию|по умолчанию]].
Строка 17:
При вызове функции задаются [[w:Фактический аргумент|фактические аргументы]]. Например:
 
<sourcesyntaxhighlight lang="python">
func(2, y=7)
</syntaxhighlight>
</source>
 
В начале идут [[w:позиционные аргументы|позиционные аргументы]]. Они сопоставляются с именами формальных аргументов по порядку. Затем следуют [[w:именованные аргументы|именованные аргументы]]. Они сопоставляются по именам и могут быть заданы в вызове функции в любом порядке. Разумеется, все аргументы, для которых в описании функции не указаны значения по умолчанию, должны присутствовать в вызове функции. Повторы в именах аргументов недопустимы.
Строка 26:
 
Определив функцию с помощью [[w:лямбда-исчисление|лямбда-выражения]], можно тут же её использовать:
<sourcesyntaxhighlight lang="python">
>>> (lambda x: x+2)(5)
7
</syntaxhighlight>
</source>
 
Лямбда-выражения удобны для определения не очень сложных функций, которые передаются затем другим функциям.
Строка 37:
=== Списковые включения ===
[[w:Списковое включение]]{{sfn|Прохоренок|2011|с=123-124}} ({{lang-en|list comprehension}}) — наиболее выразительное из функциональных средств Python. Например, для вычисления списка квадратов положительных целых чисел, меньших 10, можно использовать выражение:
<sourcesyntaxhighlight lang="python">
l = [x**2 for x in range(1,10)]
</syntaxhighlight>
</source>
 
=== Встроенные [[w:Функция высшего порядка|функции высших порядков]] ===
Строка 48:
Функция <code>map()</code> позволяет обрабатывать одну или несколько последовательностей с помощью заданной функции:
 
<sourcesyntaxhighlight lang="python">
>>> 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]
</syntaxhighlight>
</source>
 
Аналогичного (только при одинаковой длине списков) результата можно добиться с помощью списочных выражений:
 
<sourcesyntaxhighlight lang="python">
>>> [x*y for x, y in zip(list1, list2)]
[-7, 2, -15, 40, 72]
</syntaxhighlight>
</source>
 
==== filter() ====
Функция <code>filter()</code> позволяет фильтровать значения последовательности. В результирующем списке только те значения, для которых значение функции для элемента истинно:
 
<sourcesyntaxhighlight lang="python">
>>> numbers = [10, 4, 2, -1, 6]
>>> filter(lambda x: x < 5, numbers) # В результат попадают только те элементы x, для которых x < 5 истинно
[4, 2, -1]
</syntaxhighlight>
</source>
 
То же самое с помощью списковых выражений:
 
<sourcesyntaxhighlight lang="python">
>>> numbers = [10, 4, 2, -1, 6]
>>> [x for x in numbers if x < 5]
[4, 2, -1]
</syntaxhighlight>
</source>
 
==== reduce() ====
Для организации цепочечных вычислений в списке можно использовать [[w:Свёртка списка|функцию <code>reduce()</code>]]. Например, произведение элементов списка может быть вычислено так (Python 2):
 
<sourcesyntaxhighlight lang="python">
>>>from functools import reduce
>>>numbers = [2, 3, 4, 5, 6]
>>> reduce(lambda res, x: res*x, numbers, 1)
720
</syntaxhighlight>
</source>
 
Вычисления происходят в следующем порядке:
 
<sourcesyntaxhighlight lang="python">
(((2*3)*4)*5)*6
</syntaxhighlight>
</source>
 
Цепочка вызовов связывается с помощью промежуточного результата (<code>res</code>). Если список пустой, просто используется третий параметр (в случае произведения нуля множителей это 1):
 
<sourcesyntaxhighlight lang="python">
>>> reduce(lambda res, x: res*x, [], 1)
1
</syntaxhighlight>
</source>
 
Разумеется, промежуточный результат необязательно число. Это может быть любой другой тип данных, в том числе и список. Следующий пример показывает ''реверс'' списка:
 
<sourcesyntaxhighlight lang="python">
>>> reduce(lambda res, x: [x]+res, [1, 2, 3, 4], [])
[4, 3, 2, 1]
</syntaxhighlight>
</source>
 
Для наиболее распространенных операций в Python есть встроенные функции:
 
<sourcesyntaxhighlight lang="python">
>>> numbers = [1, 2, 3, 4, 5]
>>> sum(numbers)
Строка 117:
>>> list(reversed(numbers))
[5, 4, 3, 2, 1]
</syntaxhighlight>
</source>
 
В Python 3 встроенной функции <code>reduce()</code> нет, но её можно найти в модуле <code>functools</code>.
Строка 124:
Функция для применения другой функции к позиционным и именованным аргументам, заданным списком и словарем соответственно (Python 2):
 
<sourcesyntaxhighlight lang="python">
>>> def f(x, y, z, a=None, b=None):
... print x, y, z, a, b
Строка 130:
>>> apply(f, [1, 2, 3], {'a': 4, 'b': 5})
1 2 3 4 5
</syntaxhighlight>
</source>
 
В Python 3 вместо функции <code>apply()</code> следует использовать специальный синтаксис:
 
<sourcesyntaxhighlight lang="python">
>>> def f(x, y, z, a=None, b=None):
... print(x, y, z, a, b)
Строка 140:
>>> f(*[1, 2, 3], **{'a': 4, 'b': 5})
1 2 3 4 5
</syntaxhighlight>
</source>
 
=== Замыкания ===
Строка 146:
Функции, определяемые внутри других функций, представляют собой полноценные [[w:Замыкание (программирование)|замыкания]] ({{lang-en|closures}})<ref>[http://www.diveinto.org/python3/generators.html Dive into Python 3, Ch. 6. Closures and Generators]</ref>:
 
<sourcesyntaxhighlight lang="python">
def multiplier(n):
"multiplier(n) возвращает функцию, умножающую на n"
Строка 155:
# multiplier = lambda n: lambda k: n*k
mul2 = multiplier(2) # mul2 - функция, умножающая на 2, например, mul2(5) == 10
</syntaxhighlight>
</source>
 
=== Итераторы ===
Строка 162:
 
Следующий пример иллюстрирует применение перечисляющего и сортирующего [[w:итератор (программирование)|итератор]]ов (итератор не может быть напечатан оператором <code>print</code>, поэтому оставшиеся в нем значения были помещены в список):
<sourcesyntaxhighlight lang="python">
>>> it = enumerate(sorted("PYTHON")) # итератор для перечисленных отсортированных букв слова
>>> it.next() # следующее значение
Строка 168:
>>> print list(it) # оставшиеся значения в виде списка
[(1, 'N'), (2, 'O'), (3, 'P'), (4, 'T'), (5, 'Y')]
</syntaxhighlight>
</source>
 
Следующий пример иллюстрирует использование модуля <code>itertools</code>:
 
<sourcesyntaxhighlight lang="python">
>>> from itertools import chain
>>> print list(chain(iter("ABC"), iter("DEF")))
['A', 'B', 'C', 'D', 'E', 'F']
</syntaxhighlight>
</source>
 
В следующем примере иллюстрируется функция <code>groupby</code> (группировать по), с помощью которой порождается список пар значение ключа и соответствующий ключу итератор (в этот итератор собраны все значения исходного списка с одинаковым значением ключа). В примере ключом является True или False в зависимости от положительности значения. (Для целей вывода каждый итератор превращается в список).
 
<sourcesyntaxhighlight lang="python">
from math import cos
from itertools import groupby
lst = [cos(x*.4) for x in range(30)] # косинусоида
[list(y) for k, y in groupby(lst, lambda x: x > 0)] # группы положительных и отрицательных чисел
</syntaxhighlight>
</source>
 
В модуле <code>itertools</code> есть и другие функции для работы с итераторами, позволяющие кратко (в функциональном стиле) и с вычислительной точки зрения — эффективно — выразить требуемые процессы обработки списков.
Строка 192:
 
В Python 2.5 появился модуль <code>functools</code> и в частности возможность ''частичного применения функций'':
<sourcesyntaxhighlight lang="python">
>>> from functools import partial
>>> def myfun(a, b): return a + b
Строка 199:
>>> print myfun1(2)
3
</syntaxhighlight>
</source>
(Частичное применение функций также можно реализовать с помощью
[[#Замыкания|замыканий]] или
Строка 216:
Пример, который иллюстрирует работу if-выражения. С помощью оператора <code>print</code> можно проследить, какие функции реально вызывались:
 
<sourcesyntaxhighlight lang="python">
>>> def f():
... print "f"
Строка 231:
g
'g'
</syntaxhighlight>
</source>
 
Некоторые примеры из книги рецептов:
Строка 249:
Ниже представлено замыкание и эквивалентный ему функтор:
 
<sourcesyntaxhighlight lang="python">
 
def addClosure(val1):
Строка 266:
 
print cl(1), fn(1) # напечатает "3 3"
</syntaxhighlight>
</source>
 
Следует отметить, что код, использующий замыкание, будет исполняться быстрее, чем код с функтором. Это связанно с необходимостью получения атрибута <code>val</code> у переменной <code>self</code> (то есть функтор проделывает на одну Python операцию больше).
Строка 273:
Для этого достаточно соответствующим образом перегрузить специальные методы.
 
<sourcesyntaxhighlight lang="Python">
class SlowFunctor(object):
def __init__(self,func):
Строка 302:
print func(math.pi) # печатает 3.14159265359
print func(math.pi) - func2(math.pi) # печатает 0.0
</syntaxhighlight>
</source>
 
Функторы привносят в Python возможность [[w:Ленивые вычисления|ленивых вычислений]], присущую функциональным языкам: вместо вычисления результата выражения — динамическое определение новых функций комбинированием имеющихся.