Функциональное программирование

lambda, ФВП, map(), reduce(), filter(), zip(), enumerate()

Введение

Функциональное программирование — это такая методика написания программ, когда в центре внимания находятся функции. Функции могут присваиваться переменным, они могут передаваться в другие функции и порождать новые функции. Это можно назвать стилем или парадигмой программирования

В этой парадигме широко используются функции высшего порядка и анонимные функции

Функции высшего порядка (ФВП) — это функции, которые принимают в качестве аргумента другие функции и/или возвращают функции в качестве результата. Мы коснулись их в прошлом уроке, а в этой главе познакомимся поближе

Анонимные функции (lambda-функции) — безымянные функции

Анонимные функции (lambda)

Вспомним:

  • Функции — это небольшие подпрограммы внутри основного кода. При запуске они могут взять какие-то стартовые параметры, обработать их, получить свой результат и отдать этот результат в основной код

  • Чтобы вызвать функцию, нужно указать её имя, но бывают такие функции, у которых нет имени, но их всё равно можно вызывать

Пример обычной функции:

def add_func(x, y):
    result = x + y
    return result
print(add_func(2,3))
  • У функции есть имя, тело функции и есть результат, который она возвращает. Чтобы вызвать эту функцию, мы указываем имя и аргументы, которые нужно обработать.

  • Мы можем значительно усложнить функцию, для этого добавить в неё нужные инструкции

Лямбда-функции выглядят по-другому — они не имеют имени, но у них есть ключевое слово lambda.

  • lambda аргументы: выражение (значение функции)

  • лямбда-функция всегда возвращает значение

  • она должна быть записана в одну строку

  • внутри функций нет присваивания и сложной логики — это всегда простое выражение

Зачем нужны лямбда-функции?

  • Самое частое применение — в качестве аргументов в других функциях

  • Пример:

  • Пойдём дальше — мы можем вместо filter_numbers тоже использовать лямбда-функцию:

  • Технически, можно обойтись без лямбда-функций. Но иногда с ними получается удобнее

Практика:

  • Напишите четыре анонимные функции. Они должны:

    • Возводить переданное число в квадрат

    • Умножать два переданных числа

    • Возвращать бОльшее из двух переданных чисел

    • Возвращать первую букву переданного слова

  • Выведите на экран результат работы этих функций

Встроенные ФВП: map() filter() reduce()

map()

  • Допустим, мы хотим применить к каждому элементу списка какую-то функцию или операцию. Мы можем сделать при помощи цикла for:

  • Можем определить две функции, одна из которых принимает последовательность и функцию, а вторая является той функцией, которую нужно применить:

  • Есть третий способ — использовать встроенную функцию высшего порядка map()

  • Она принимает в качестве аргументов функцию и последовательность. И применяет переданную функцию к каждому элементу последовательности

  • Часто вместе в качестве аргументов для ФВП используют анонимные функции:

filter()

  • Как мы видим из сигнатуры, функция принимает функцию или None и итерируемую последовательность. Возвращает объект filter

  • filter() принимает функцию, которая возвращает булево значение

  • Попробуйте передать в качестве аргумента вместо функции значение None. Проанализируйте результат

reduce()

  • Для того, чтобы воспользоваться функцией reduce()нам понадобится импортировать её из модуля functools

  • Функция reduce() кумулятивно применяет функцию function к элементам итерируемой iterable последовательности, сводя её к единственному значению

  • По сути результат работы reduce() это аккумулятор

  • Необязательный аргумент initializer — это значение аккумулятора по умолчанию, с которого начать работу. Если последовательность пустая, аккумулятор примет значение initializer. Если последовательность непустая, то initializer станет начальным значением аккумулятора

  • Попробуйте применить аргумент initializer к примерам выше. Проанализируйте результат

Особенности объектов map, filter, reduce

  • Результат работы функций map() filter() reduce() это объекты map filter reduce соответственно. Это не готовые последовательности, а итераторы — интерфейсы для взаимодействия с последовательностями, но не сами последовательности.

  • Мы можем использовать их как iterable объекты, но не можем увидеть всю последовательность.

  • Сама последовательность скрыта и данные предоставляются "по запросу" — то есть только тогда, когда это потребуется

  • Это позволяет эффективнее использовать память, чем при хранении, например, списка

  • Если нам нужна сама последовательность, результат работы map() filter() reduce() нужно преобразовать в неё

Практика:

Задание с числами:

  • Входные данные: список чисел.

  • Используйте map(), чтобы возвести каждое число в квадрат.

  • Затем к получившейся последовательности примените filter(), чтобы отфильтровать только нечётные числа.

  • И к получившейся в результате последней операции последовательности примените reduce(), чтобы сложить оставшиеся числа в списке.

Задание с текстом:

  • Входные данные: список строк. Также как в прошлом задании, последовательно примените функции к списку строк.

    • Используйте map(), чтобы преобразовать каждую строку в верхний регистр.

    • Используйте filter(), чтобы отфильтровать строки, которые содержат определенную подстроку

    • Используйте reduce(), чтобы объединить отфильтрованные строки в одну строку через запятую.

    • Верните результат.

  • Для тестирования используйте следующие данные:

Некоторые полезные функции

zip()

  • Функция zip() — объединяет отдельные элементы нескольких последовательностей в кортежи. Возвращает объект zip

  • Примеры использования:

  • Попробуйте применить zip() к последовательностям разной длины. Проанализируйте результат

  • zip() часто используется для создания словарей. В главе, посвященной словарям, мы узнаем, как это работает

enumerate()

  • Функция enumerate возвращает индекс элемента и сам элемент последовательности в качестве кортежа. Вот общий формат функции enumerate:

  • Пример использования:

  • enumerate() часто используют в цикле for, когда нам нужен и элемент и его индекс:

Практика:

  • Напишите функцию, которая принимает на вход список чисел и возвращает новый список, состоящий из чисел, имеющих четный индекс. Используйте enumerate()

Last updated