Как сделать лямбда-зонт
hard

Как сделать лямбда-зонт

Рассказываем про лямбда-функции в типичных задачах

В прошлый раз мы рассказывали о том, что такое лямбда-функции и чем они полезны в программировании. Сегодня сделаем второй заход и рассмотрим несколько ситуаций с использованием лямбда-функций в Python. Заодно выясним, когда они могут выручить, а когда можно и без них.

Что такое лямбда-функции

Лямбда-функции — это анонимные функции, которые создаются с помощью ключевого слова lambda. Их используют, когда нужно определить небольшую функцию на месте и применить её разово. Стандартный синтаксис лямбда-функции такой:

lambda переменные: значение функции

У лямбда-функций есть ограничения:

  • Значение должно быть записано в одну строку (внутри не может быть циклов, других функций и всего остального, что требует для записи несколько строк). 
  • Функция обязательно возвращает какое-то значение.
  • Это простое выражение, в котором нет присваивания, поэтому оно ничего не хранит, а лишь считает.

Теперь — к реальным примерам.

Использование в функциях высшего порядка

Функция высшего порядка — это функция, которая принимает другую функцию в качестве аргумента или возвращает её как результат. Например, у нас есть числовое значение и мы хотим применить к нему несколько математических операций: возвести в квадрат, куб и умножить на 2. Без лямбда-функции можно сделать это так:

def square(x):
    return x ** 2

def cube(x):
    return x ** 3

def doubling(x):
    return x * 2

def apply_function(x, func):
    return func(x)

result_square = apply_function(5, square)
result_cube = apply_function(5, cube)
result_double = apply_function(5, doubling)

print(result_square)
print(result_cube)
print(result_double)

Что мы здесь делаем:

  1. Определяем функцию square для возведения в квадрат.
  2. Определяем функцию cube для возведения в куб.
  3. Определяем функцию doubling для умножения на 2.
  4. Указываем, с помощью какой функции посчитать квадрат.
  5. Указываем, с помощью какой функции посчитать куб.
  6. Указываем, с помощью какой функции посчитать умножение на 2.

А вот что будет с лямбда-функцией:

def apply_function(x, func):
    return func(x)

result_square = apply_function(5, lambda x: x ** 2)
result_cube = apply_function(5, lambda x: x ** 3)
result_double = apply_function(5, lambda x: x * 2)

print(result_square)
print(result_cube)
print(result_double)

Что здесь происходит:

  1. Определяется функция apply_function для применения различных операций к числу.
  2. Лямбда-функция lambda x: x ** 2 принимает одно значение x и возвращает его квадрат (x2).
  3. Лямбда-функция lambda x: x ** 3 принимает одно значение x и возвращает его куб ().
  4. Лямбда-функция lambda x: x * 2 принимает одно значение x и возвращает его умножение на 2 (x*2).

Создание словаря с функциями

Предыдущий пример можно реализовать ещё изящнее с помощью лямбда-функций в словаре. Представим, что нам нужно складывать, вычитать, умножать и делить два числовых значения. Для этого можно создать словарь, в котором ключами будут строки из команд или операций, а значениями — лямбда-функции, которые выполняют соответствующие действия. После создания такого словаря можно легко вызывать нужные функции по ключам:

operations = {
    'add': lambda x, y: x + y,
    'subtract': lambda x, y: x - y,
    'multiply': lambda x, y: x * y,
    'divide': lambda x, y: x / y if y != 0 else 'Ошибка деления на ноль!'
}

a, b = 10, 5
operation = 'multiply'
result = operations[operation](a, b)
print(result)

Что здесь происходит:

  1. Создаётся словарь operations, в котором ключи — это строки из названий операций add, substract, multiply и divide, а значения — лямбда-функции с соответствующими формулами.
  2. Определяются переменные a и b со значениями 10 и 5 соответственно.
  3. Выбираем, какую из операций в словаре хотим выполнить с этими переменными.

Использование с функцией map

Функцию map применяют, чтобы преобразовать элементы какой-то последовательности с использованием другой функции. Например, у нас есть список чисел, каждое из которых нужно возвести в квадрат. Без лямбда-функции это можно сделать так:

def square(x):
    return x ** 2

numbers = [1, 2, 3, 4, 5]
squared = list(map(square, numbers))
print(squared)

Что мы здесь делаем:

  1. Определяем функцию, которая принимает одно значение x и возвращает его квадрат.
  2. Передаём функцию square в map, чтобы она применилась к каждому элементу списка.
  3. Преобразуем результат в список, сохраняя его в переменной squared.

А вот как сокращается код, если использовать лямбда-функцию:

numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x ** 2, numbers))
print(squared)

Что здесь происходит:

  1. Функция map применяет функцию, заданную лямбда-выражением lambda x: x ** 2, к каждому элементу списка.
  2. Лямбда-функция lambda x: x ** 2 принимает одно значение x и возвращает его квадрат.
  3. Результат преобразуется в список и сохраняется в переменной squared.

Использование с функцией filter

Функция filter применяется для фильтрации элементов последовательности с использованием другой функции. Например, мы работаем с данными и нам нужно быстро отфильтровать список с идентификаторами пользователей, отделив от него чётные. Без лямбда-функции нам потребуется такой код:

def is_even(x):
    return x % 2 == 0

user_ids = [101, 202, 303, 404, 505, 606, 707, 808, 909, 1000]
even_user_ids = list(filter(is_even, user_ids))
print(even_user_ids)

Что мы здесь делаем:

  1. Определяем функцию is_even, которая принимает одно значение x и возвращает True, если оно чётное.
  2. Передаём функцию is_even в filter, чтобы она применялась к каждому элементу списка.
  3. Преобразуем результат в список, сохраняя его в переменной even_user_ids.

А вот как сделать то же самое с лямбда-функцией:

user_ids = [101, 202, 303, 404, 505, 606, 707, 808, 909, 1000]
even_user_ids = list(filter(lambda x: x % 2 == 0, user_ids))
print(even_user_ids)

Что здесь происходит:

  1. Функция filter применяет функцию, заданную лямбда-выражением lambda x: x % 2 == 0, к каждому элементу списка, возвращая только те элементы, для которых эта функция возвращает True.
  2. Лямбда-функция lambda x: x % 2 == 0 принимает одно значение x и возвращает True, если x чётное.
  3. Результат преобразуется в список и сохраняется в переменной even_user_ids.

Сортировка списка кортежей

С помощью сортировки можно сортировать данные по определённому критерию. Например, у нас есть кортеж с идентификатором и названием продуктов, и нам нужно отсортировать этот набор данных по названию продукта. Без лямбда-функции код будет таким:

def get_second_element(tuple):
    return tuple[1]

products = [(101, 'apple'), (303, 'banana'), (202, 'cherry')]
sorted_products = sorted(data, key=get_second_element)
# выводим результат на экран
print(sorted_products)

Что мы здесь делаем:

  1. Определяем функцию get_second_element, которая принимает кортеж и возвращает его второй элемент.
  2. Передаём функцию get_second_element в sorted как элемент сортировки.
  3. Делаем сортировку на основе второго элемента каждого кортежа и сохраняем результат в переменной sorted_products.

А вот как упростить код с лямбда-функцией:

products = [(101, 'apple'), (303, 'banana'), (202, 'cherry')]
sorted_products = sorted(products, key=lambda x: x[1])
print(sorted_products)  # [(101, 'apple'), (303, 'banana'), (202, 'cherry')]

Что здесь происходит:

  1. Функция sorted сортирует элементы списка по ключу, заданному лямбда-выражением lambda x: x[1].
  2. Лямбда-функция lambda x: x[1] принимает кортеж x и возвращает его второй элемент (индекс 1).
  3. Выполняется сортировка на основе второго элемента каждого кортежа, результат сохраняется в sorted_products.

Использование с Tkinter

С помощью библиотеки Tkinter можно создавать графические интерфейсы с различными элементами, например кнопками. При этом каждую кнопку чаще всего нужно описать только один раз. Представим, что мы создаём таск-трекер — приложение для отслеживания задач. В приложении должна быть кнопка «Добавить задачу», которая при нажатии выводит в консоль сообщение «Задача добавлена». Без лямбда-функции мы можем сделать это так:

import tkinter as tk

def on_button_click():
    print("Задача добавлена")

root = tk.Tk()

button = tk.Button(root, text="Добавить задачу", command=on_button_click)
button.pack()

root.mainloop()

Что мы здесь делаем:

  1. Импортируем библиотеку Tkinter.
  2. Определяем функцию on_button_click, которая выводит текст «Задача добавлена» при нажатии кнопки.
  3. Создаём главное окно приложения.
  4. Добавляем кнопку tk.Button с подписью «Добавить задачу».
  5. Отображаем кнопку в главном окне.
  6. Запускаем основной цикл обработки событий.

А вот как можно сделать такое же с лямбда-функцией:

import tkinter as tk

root = tk.Tk()

button = tk.Button(root, text="Задача добавлена", command=lambda: print("Добавить задачу"))
button.pack()

root.mainloop()

Что здесь происходит:

  1. Импортируется библиотека Tkinter.
  2. Создаётся главное окно приложения.
  3. Создаётся кнопка с текстом «Добавить задачу». Аргумент command задаёт функцию, которая будет выполнена при нажатии кнопки.
  4. Кнопка отображается в главном окне.
  5. Запускается основной цикл обработки событий.

Так лучше с лямбда-функциями или без них?

На самом деле, использовать лямбда-функции не обязательно, но они дают множество преимуществ:

  • Помогают не засорять код дополнительными именованными функциями, которые больше нигде не используются.
  • Позволяют не объявлять явно небольшие одноразовые функции, что делает код короче и менее громоздким.
  • Делают код более читаемым, ведь вся логика видна в строке использования функции.

Обложка:

Алексей Сухов

Корректор:

Ирина Михеева

Вёрстка:

Маша Климентьева

Соцсети:

Юлия Зубарева

Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.
Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию
Еще по теме
hard