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

Содержимое удалено Содержимое добавлено
оформление ВУ
Строка 1:
[[w:Функциональное программирование|Функциональное программирование]] является одной из парадигм, поддерживаемых языком программирования [[w:Python|Python]]. Основными предпосылками для полноценного функционального программирования в Python являются: [[w:Функция высшего порядка|функции высших порядков]], развитые средства [[w:Обработка списков|обработки списков]], [[w:Рекурсия#Рекурсия в программировании|рекурсия]], возможность организации [[w:Ленивые вычисления|ленивых вычислений]]. Элементы функционального программирования в Python могут быть полезны любому программисту, так как позволяют гармонично сочетать выразительную мощность этого подхода с другими подходами.
 
== Возможности ==
=== Определение и использование функции ===
 
Функция в Python может быть определена с помощью оператора <code>def</code> или [[w:Лямбда-выражения|лямбда-выражением]]. Следующие операторы эквивалентны:
 
<source lang="python">
Строка 13:
</source>
 
В определении функции фигурируют [[w:Формальный аргумент|формальные аргументы]]. Некоторые из них могут иметь значения по умолчанию. Все аргументы со значениями по умолчанию следуют после аргументов без значений [[w:по умолчанию|по умолчанию]].
 
При вызове функции задаются [[w:Фактический аргумент|фактические аргументы]]. Например:
 
<source lang="python">
Строка 21:
</source>
 
В начале идут [[w:позиционные аргументы|позиционные аргументы]]. Они сопоставляются с именами формальных аргументов по порядку. Затем следуют [[w:именованные аргументы|именованные аргументы]]. Они сопоставляются по именам и могут быть заданы в вызове функции в любом порядке. Разумеется, все аргументы, для которых в описании функции не указаны значения по умолчанию, должны присутствовать в вызове функции. Повторы в именах аргументов недопустимы.
 
Функция всегда возвращает только одно значение (или <code>None</code>, если значение не задано в операторе <code>return</code> или этот оператор не встречен по достижении конца определения функции). Однако, это незначительное ограничение, так как возвращаемым значением может быть [[w:кортеж (информатика)|кортеж]].
 
Определив функцию с помощью [[w:лямбда-исчисление|лямбда-выражения]], можно тут же её использовать:
<source lang="python">
>>> (lambda x: x+2)(5)
Строка 33:
Лямбда-выражения удобны для определения не очень сложных функций, которые передаются затем другим функциям.
 
Функции в Python являются [[w:Объект первого класса|объектами первого класса]], то есть, они могут употребляться в программе наравне с объектами других типов данных.
 
=== Списковые включения ===
[[w:Списковое включение]]{{sfn|Прохоренок|2011|с=123-124}} ({{lang-en|list comprehension}}) — наиболее выразительное из функциональных средств Python. Например, для вычисления списка квадратов положительных целых чисел, меньших 10, можно использовать выражение:
<source lang="python">
l = [x**2 for x in range(1,10)]
</source>
 
=== Встроенные [[w:Функция высшего порядка|функции высших порядков]] ===
 
В Python есть функции, одним из аргументов которых являются другие функции: <code>map()</code>, <code>filter()</code>, <code>reduce()</code>, <code>apply()</code>.
Строка 80:
 
==== reduce() ====
Для организации цепочечных вычислений в списке можно использовать [[w:Свёртка списка|функцию <code>reduce()</code>]]. Например, произведение элементов списка может быть вычислено так (Python 2):
 
<source lang="python">
Строка 144:
=== Замыкания ===
 
Функции, определяемые внутри других функций, представляют собой полноценные [[w:Замыкание (программирование)|замыкания]] ({{lang-en|closures}})<ref>[http://www.diveinto.org/python3/generators.html Dive into Python 3, Ch. 6. Closures and Generators]</ref>:
 
<source lang="python">
Строка 161:
Другие средства функционального программирования доступны из стандартной библиотеки (например, модуль <code>itertools</code>) и других библиотек.
 
Следующий пример иллюстрирует применение перечисляющего и сортирующего [[w:итератор (программирование)|итератор]]ов (итератор не может быть напечатан оператором <code>print</code>, поэтому оставшиеся в нем значения были помещены в список):
<source lang="python">
>>> it = enumerate(sorted("PYTHON")) # итератор для перечисленных отсортированных букв слова
Строка 201:
</source>
(Частичное применение функций также можно реализовать с помощью
[[Функциональное программирование на Python#Замыкания|замыканий]] или
[[Функциональное программирование на Python#Функторы|функторов]])
 
=== Ленивые вычисления ===
 
[[w:Ленивые вычисления|Ленивые вычисления]] можно организовать в Python несколькими способами, используя различные механизмы:
 
* простейшие логические операции or и and не вычисляют второй операнд, если результат определяется первым операндом
* [[w:лямбда-исчисление|лямбда-выражения]]
* определенные пользователем классы с ленивой логикой вычислений<ref name="lazypy">[http://freshmeat.net/projects/lazypy/ Пакет lazypy]</ref> или [[w:Функциональное программирование на Python#Функторы|функторы]]
* [[w:Python#Генераторы|Генераторы и генераторные выражения]]
* (Python 2.5) if-выражение имеет «ленивую» семантику (вычисляется только тот операнд, который нужен)
 
Строка 241:
=== Функторы ===
 
[[w:Функтор (программирование)|Функторами]] называют объекты, синтаксически подобные функциям, то есть поддерживающие операцию вызова.
Для определения функтора нужно перегрузить оператор <code>()</code> с помощью метода <code>__call__</code>. В
Python функторы полностью аналогичны функциям, за исключением специальных атрибутов
(<code>func_code</code> и некоторых других). Например, функторы можно передавать в качестве [[w:Callback (программирование)|функций
обратного вызова (callback)]] в С-код. Функторы позволяют заменить некоторые приёмы, связанные с использованием замыкания, статических переменных и т. п.
 
Строка 269:
 
Следует отметить, что код, использующий замыкание, будет исполняться быстрее, чем код с функтором. Это связанно с необходимостью получения атрибута <code>val</code> у переменной <code>self</code> (то есть функтор проделывает на одну Python операцию больше).
Также функторы нельзя использовать для создания [[w:Python#Декораторы|декораторов]] с параметрами.
С другой стороны, функторам доступны все возможности ООП в Python, что делает их очень полезными для функционального программирования. Например, можно написать функтор, который будет «запоминать» исполняемые над ним операции и затем повторять их.
Для этого достаточно соответствующим образом перегрузить специальные методы.
Строка 304:
</source>
 
Функторы привносят в Python возможность [[w:Ленивые вычисления|ленивых вычислений]], присущую функциональным языкам: вместо вычисления результата выражения — динамическое определение новых функций комбинированием имеющихся.
 
Определенный подобным образом функтор создает значительные накладные расходы, так как при каждом вызове
проходит по вызовам всех вложенных <code>lambda</code>. Можно оптимизировать функтор,
применив технику генерирования байткода во время исполнения. Соответствующий пример и тесты на скорость
есть в [[w:v:Примеры программ на языке Python#Функтор с генерацией байтокода|Примерах Python программ]].
При использовании этой техники скорость исполнения не будет отличаться от «статического» кода (если не считать времени, требующегося на однократное конструирование результирующей функции).
Вместо байтокода Python можно генерировать на выходе, например, код на языке программирования
[[w:Си (язык программирования)|C]], других языках программирования или [[w:XML|XML]]-файлы.
 
Несмотря на накладные расходы, ленивое вычисление может дать заметный выигрыш в скорости в случаях, когда действия, оборачиваемые ленивым функтором, достаточно дороги — например, включают объёмные вычисления или доступ к диску. Предположим некоторый промежуточный результат ''X'' лениво вычисляется перед условным оператором; для него будет создана цепочка функторов. В той ветке условного оператора, где значение ''X'' не требуется по ходу вычисления, эта цепочка функторов будет просто отброшена, не приведя к дорогостоящему вычислению. В другой ветке, где ''X'' требуется для вычисления конечного результата функции, цепочка функторов произведёт его вычисление. При этом программисту не нужно отслеживать, в какой из веток алгоритма значение может не потребоваться: он может рассчитывать, что дорогостоящее вычисление ''X'' произойдёт только тогда, когда его результат не будет отброшен.
Строка 342:
 
{{rq|refless|wikify|sources}}
{{BookCat}}
 
[[Категория:Python]]
[[Категория:Функциональное программирование]]