← Все вопросы

Что такое lambda в Python и зачем она нужна, если есть обычные функции через def?

Задан 6 дней назад392 просмотров2 ответа
6

Постоянно вижу в чужом коде такие штуки: sorted(users, key=lambda u: u.age). Что это за lambda? Вроде какая-то функция, но без имени и без def. Не понимаю, зачем вообще нужна, если можно написать нормальную функцию. Когда её уместно использовать, а когда нет?

2 ответа

4
✓ Принятый ответ — помог автору

lambda — это способ создать маленькую анонимную функцию прямо в одну строку, без def и без имени. Синтаксис такой:

lambda аргументы: выражение

Результат выражения автоматически возвращается (никакого return писать не надо). Вот две полностью эквивалентные функции:

def square(x):
    return x * x

square2 = lambda x: x * x

square(5)   # 25
square2(5)  # 25

Но хранить лямбду в переменной — плохой стиль (для этого есть def). Её сила — когда нужна функция на один раз, которую передают как аргумент. Самый частый случай — параметр key= в sorted, max, min:

users = [("Аня", 30), ("Боб", 25), ("Вера", 28)]

# сортировка по возрасту (второй элемент кортежа)
print(sorted(users, key=lambda u: u[1]))
# [('Боб', 25), ('Вера', 28), ('Аня', 30)]

# самый старший
print(max(users, key=lambda u: u[1]))   # ('Аня', 30)

Здесь key говорит: «по какому признаку сравнивать элементы». Лямбда достаёт этот признак. Заводить ради этого отдельную именованную функцию — избыточно.

Также лямбды часто суют в map и filter:

nums = [1, 2, 3, 4]
list(map(lambda x: x * 2, nums))            # [2, 4, 6, 8]
list(filter(lambda x: x % 2 == 0, nums))    # [2, 4]

Хотя тут многие питонисты предпочтут списочные включения как более читаемые: [x * 2 for x in nums].

Когда лучше обычный def: если логика не помещается в одно выражение, нужны несколько строк, if/else-ветвления или просто хочется внятное имя для отладки. Лямбда хороша ровно для коротких одноразовых выражений — не пытайся впихнуть в неё много логики.

0

Подсвечу классическую ловушку с лямбдами в цикле — она реально кусает новичков:

funcs = [lambda: i for i in range(3)]
print([f() for f in funcs])   # [2, 2, 2], а НЕ [0, 1, 2]

Лямбда захватывает переменную i по ссылке, а не её значение в момент создания. К моменту вызова цикл закончился и i == 2. Лечится привязкой через аргумент по умолчанию:

funcs = [lambda i=i: i for i in range(3)]
print([f() for f in funcs])   # [0, 1, 2]

И ещё мелочь по стилю: PEP 8 не рекомендует присваивать лямбду переменной (f = lambda x: ...). Если нужно имя — пиши def.

Ваш ответ

Войдите, чтобы ответить на вопрос.
Поддержать проект