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

Содержимое удалено Содержимое добавлено
→‎filter(): орфография с помощью AWB
Нет описания правки
Строка 39:
=== Списочные выражения ===
 
Списочные выражения (''list comprehension'', иногда используется термин "«списковые включения"»)  — наиболее выразительное из функциональных средств Питона. Например, для вычисления списка квадратов натуральных чисел, меньших 10, можно использовать выражение:
<source lang="python">
l = [x**2 for x in range(10)]
Строка 162:
=== Итераторы ===
 
Другие средства функционального программирования доступны из стандартной библиотеки (например, модуль <code>itertools</code>) и других библиотек.
 
Следующий пример иллюстрирует применение перечисляющего и сортирующего [[Итератор|итераторов]] (итератор не может быть напечатан оператором <code>print</code>, поэтому оставшиеся в нем значения были помещены в список):
Строка 190:
</source>
 
В модуле <code>itertools</code> есть и другие функции для работы с итераторами, позволяющие кратко (в функциональном стиле) и с вычислительной точки зрения - — эффективно - — выразить требуемые процессы обработки списков.
 
=== Модуль functools ===
Строка 203:
3
</source>
(Частичное применение функций также можно реализовать с помощью
[[Функциональное программирование на Питоне#Замыкания|замыканий]] или
[[Функциональное программирование на Питоне#Функторы|функторов]] )
 
=== Ленивые вычисления ===
Строка 215:
* определенные пользователем классы с ленивой логикой вычислений<ref name="lazypy">[http://freshmeat.net/projects/lazypy/ Пакет lazypy]</ref> или [[Функциональное программирование на Питоне#Функторы|функторы]]
* [[Python#Генераторы|Генераторы и генераторные выражения]]
* (Python 2.5) if-выражение имеет "«ленивую"» семантику (вычисляется только тот операнд, который нужен)
 
Пример, который иллюстрирует работу if-выражения. С помощью оператора <code>print</code> можно проследить, какие функции реально вызывались:
Строка 246:
 
Функторами называют объекты, синтаксически подобные функциям, то есть поддерживающие операцию вызова.
Для определения функтора нужно перегрузить оператор <code>()</code> с помощью метода <code>__call__</code>. В
Python функторы полностью аналогичны функциям, за исключением специальных атрибутов
(<code>func_code</code> и некоторых других). Например, функторы можно передавать в качестве [[Callback (программирование)|функций
обратного вызова (callback)]] в С-код. Функторы позволяют заменить некоторые приёмы, связанные с использованием замыкания, статических переменных и  т.  п.
 
Ниже представлено замыкание и эквивалентный ему функтор:
Строка 272:
</source>
 
Следует отметить, что код, использующий замыкание, будет исполнятся быстрее, чем код с функтором. Это связанно с необходимостью получения атрибута <code>val</code> у переменной <code>self</code> (т.е.то есть функтор проделывает на одну Python операцию больше).
Также функторы нельзя использовать для создания [[Python#Декораторы|декораторов]] с параметрами.
С другой стороны, функторам доступны все возможности ООП в Python, что делает их очень полезными для функционального программирования. Например, можно написать функтор, который будет "«запоминать"» исполняемые над ним операции и затем повторять их.
Для этого достаточно соответствующим образом перегрузить специальные методы.
 
Строка 308:
</source>
 
Функторы привносят в Python возможность [[Ленивые вычисления|ленивых вычислений]], присущую функциональным языкам: вместо вычисления результата выражения  — динамическое определение новых функций комбинированием имеющихся.
 
Определенный подобным образом функтор создает значительные накладные расходы, так как при каждом вызове
проходит по вызовам всех вложенных <code>lambda</code>. Можно оптимизировать функтор,
применив технику генерирования байткода во время исполнения. Соответствующий пример и тесты на скорость
есть в [[Python примеры программ#Функтор с генерацией байтокода|Примерах Python программ]].
При использовании этой техники скорость исполнения не будет отличаться от "«статического"» кода (если не считать времени, требующегося на однократное конструирование результирующей функции).
Вместо байтокода Python можно генерировать на выходе, например, код на языке программирования
[[Си_(язык_программирования)|C]], других языках программирования или [[XML]]-файлы.
 
Несмотря на накладные расходы, ленивое вычисление может дать заметный выигрыш в скорости в случаях, когда действия, оборачиваемые ленивым функтором, достаточно дороги  — например, включают объёмные вычисления или доступ к диску. Предположим некоторый промежуточный результат ''X'' лениво вычисляется перед условным оператором; для него будет создана цепочка функторов. В той ветке условного оператора, где значение ''X'' не требуется по ходу вычисления, эта цепочка функторов будет просто отброшена, не приведя к дорогостоящему вычислению. В другой ветке, где ''X'' требуется для вычисления конечного результата функции, цепочка функторов произведёт его вычисление. При этом программисту не нужно отслеживать, в какой из веток алгоритма значение может не потребоваться: он может рассчитывать, что дорогостоящее вычисление ''X'' произойдёт только тогда, когда его результат не будет отброшен.
 
== Примечания ==