Элементы функционального программирования списковые выражения
Обновлено: 05.11.2024
Функциональное программирование является одной из парадигм, поддерживаемых языком программирования Python. Основными предпосылками для полноценного функционального программирования в Python являются: функции высших порядков, развитые средства обработки списков, рекурсия, возможность организации ленивых вычислений. Элементы функционального программирования в Python могут быть полезны любому программисту, так как позволяют гармонично сочетать выразительную мощность этого подхода с другими подходами.
Содержание
Функция в Python может быть определена с помощью оператора def или лямбда-выражением. Следующие операторы эквивалентны:
В определении функции фигурируют формальные аргументы. Некоторые из них могут иметь значения по умолчанию. Все аргументы со значениями по умолчанию следуют после аргументов без значений по умолчанию.
При вызове функции задаются фактические аргументы. Например:
В начале идут позиционные аргументы. Они сопоставляются с именами формальных аргументов по порядку. Затем следуют именованные аргументы. Они сопоставляются по именам и могут быть заданы в вызове функции в любом порядке. Разумеется, все аргументы, для которых в описании функции не указаны значения по умолчанию, должны присутствовать в вызове функции. Повторы в именах аргументов недопустимы.
Функция всегда возвращает только одно значение (или None , если значение не задано в операторе return или этот оператор не встречен по достижении конца определения функции). Однако, это незначительное ограничение, так как возвращаемым значением может быть кортеж.
Определив функцию с помощью лямбда-выражения, можно тут же её использовать:
Лямбда-выражения удобны для определения не очень сложных функций, которые передаются затем другим функциям.
Функции в Python являются объектами первого класса, то есть, они могут употребляться в программе наравне с объектами других типов данных.
В Python есть функции, одним из аргументов которых являются другие функции: map() , filter() , reduce() , apply() .
Функция map() позволяет обрабатывать одну или несколько последовательностей с помощью заданной функции:
Аналогичного (только при одинаковой длине списков) результата можно добиться с помощью списочных выражений:
Функция filter() позволяет фильтровать значения последовательности. В результирующем списке только те значения, для которых значение функции для элемента истинно:
То же самое с помощью списковых выражений:
Для организации цепочечных вычислений в списке можно использовать функцию reduce() . Например, произведение элементов списка может быть вычислено так (Python 2):
Вычисления происходят в следующем порядке:
Цепочка вызовов связывается с помощью промежуточного результата ( res ). Если список пустой, просто используется третий параметр (в случае произведения нуля множителей это 1):
Разумеется, промежуточный результат необязательно число. Это может быть любой другой тип данных, в том числе и список. Следующий пример показывает реверс списка:
Для наиболее распространенных операций в Python есть встроенные функции:
В Python 3 встроенной функции reduce() нет, но её можно найти в модуле functools .
Функция для применения другой функции к позиционным и именованным аргументам, заданным списком и словарем соответственно (Python 2):
В Python 3 вместо функции apply() следует использовать специальный синтаксис:
Другие средства функционального программирования доступны из стандартной библиотеки (например, модуль itertools ) и других библиотек.
Следующий пример иллюстрирует применение перечисляющего и сортирующего итераторов (итератор не может быть напечатан оператором print , поэтому оставшиеся в нем значения были помещены в список):
Следующий пример иллюстрирует использование модуля itertools :
В следующем примере иллюстрируется функция groupby (группировать по), с помощью которой порождается список пар значение ключа и соответствующий ключу итератор (в этот итератор собраны все значения исходного списка с одинаковым значением ключа). В примере ключом является True или False в зависимости от положительности значения. (Для целей вывода каждый итератор превращается в список).
В Python 2.5 появился модуль functools и в частности возможность частичного применения функций:
(Частичное применение функций также можно реализовать с помощью замыканий или функторов)
Ленивые вычисления можно организовать в Python несколькими способами, используя различные механизмы:
Пример, который иллюстрирует работу if-выражения. С помощью оператора print можно проследить, какие функции реально вызывались:
Некоторые примеры из книги рецептов:
Ниже представлено замыкание и эквивалентный ему функтор:
Следует отметить, что код, использующий замыкание, будет исполняться быстрее, чем код с функтором. Это связанно с необходимостью получения атрибута val у переменной self (то есть функтор проделывает на одну Python операцию больше). Также функторы нельзя использовать для создания декораторов с параметрами. С другой стороны, функторам доступны все возможности ООП в Python, что делает их очень полезными для функционального программирования. Например, можно написать функтор, который будет «запоминать» исполняемые над ним операции и затем повторять их. Для этого достаточно соответствующим образом перегрузить специальные методы.
Определенный подобным образом функтор создает значительные накладные расходы, так как при каждом вызове проходит по вызовам всех вложенных lambda . Можно оптимизировать функтор, применив технику генерирования байткода во время исполнения. Соответствующий пример и тесты на скорость есть в Примерах Python программ. При использовании этой техники скорость исполнения не будет отличаться от «статического» кода (если не считать времени, требующегося на однократное конструирование результирующей функции). Вместо байтокода Python можно генерировать на выходе, например, код на языке программирования C, других языках программирования или XML-файлы.
Читайте также: