lambda в Python — анонимные функции для аналитика

Коротко

lambda — это анонимная функция в Python. Одно выражение, без имени, без return. Аналитики используют lambda постоянно: в sorted, в pandas apply, в map/filter. На собеседованиях спрашивают синтаксис, отличия от def и подводные камни.

Синтаксис

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

lambda принимает любое количество аргументов, но содержит ровно одно выражение. Результат выражения возвращается автоматически — писать return нельзя.

# Обычная функция
def double(x):
    return x * 2

# То же самое через lambda
double = lambda x: x * 2

double(5)  # 10

Присваивать lambda переменной — антипаттерн (PEP 8 это запрещает). Если функции нужно имя, используйте def. lambda нужен там, где функция передаётся как аргумент и больше нигде не используется.

lambda в sorted и sort

Самый частый кейс — кастомная сортировка через параметр key.

employees = [
    {'name': 'Анна', 'salary': 120000},
    {'name': 'Борис', 'salary': 95000},
    {'name': 'Вика', 'salary': 140000},
]

# Сортировка по зарплате
sorted(employees, key=lambda x: x['salary'])
# [{'name': 'Борис', ...}, {'name': 'Анна', ...}, {'name': 'Вика', ...}]

# По убыванию
sorted(employees, key=lambda x: x['salary'], reverse=True)

# Сортировка кортежей по второму элементу
pairs = [(1, 'b'), (3, 'a'), (2, 'c')]
sorted(pairs, key=lambda x: x[1])
# [(3, 'a'), (1, 'b'), (2, 'c')]

sort работает так же, но меняет список на месте: employees.sort(key=lambda x: x['salary']).

lambda с map и filter

map применяет функцию к каждому элементу, filter оставляет элементы, для которых функция вернула True.

numbers = [1, 2, 3, 4, 5]

# Возвести в квадрат
list(map(lambda x: x ** 2, numbers))
# [1, 4, 9, 16, 25]

# Оставить чётные
list(filter(lambda x: x % 2 == 0, numbers))
# [2, 4]

В аналитическом коде map/filter с lambda встречаются редко — обычно вместо них используют list comprehensions:

# Читабельнее, чем map + lambda
[x ** 2 for x in numbers]

# Читабельнее, чем filter + lambda
[x for x in numbers if x % 2 == 0]

На собеседованиях знать оба варианта полезно, но в продакшен-коде comprehensions предпочтительнее.

lambda в pandas

В pandas lambda чаще всего появляется в apply, assign и сортировке.

import pandas as pd

df = pd.DataFrame({
    'name': ['Анна', 'Борис', 'Вика'],
    'salary': [90000, 150000, 110000],
    'bonus_pct': [0.10, 0.15, 0.12]
})

# apply — применить к каждому элементу столбца
df['salary_k'] = df['salary'].apply(lambda x: f"{x // 1000}k")

# apply с axis=1 — обработка строки
df['total'] = df.apply(lambda row: row['salary'] * (1 + row['bonus_pct']), axis=1)

# assign — создать столбец без мутации
df = df.assign(tax=lambda d: d['salary'] * 0.13)

# sort_values с key
df.sort_values('name', key=lambda col: col.str.lower())

Помните: apply с lambda медленнее векторных операций. df['salary'] * 1.13 быстрее, чем df['salary'].apply(lambda x: x * 1.13). Lambda в pandas — для логики, которую нельзя выразить через встроенные методы. Подробнее о группировках — в гайде по groupby.

lambda с несколькими аргументами

lambda принимает сколько угодно аргументов, включая *args и **kwargs.

# Два аргумента
add = lambda x, y: x + y
add(3, 5)  # 8

# С значением по умолчанию
greet = lambda name, prefix='Привет': f"{prefix}, {name}!"
greet('Анна')  # 'Привет, Анна!'

# В reduce — свёртка списка
from functools import reduce
reduce(lambda acc, x: acc + x, [1, 2, 3, 4])  # 10

lambda vs def — когда что использовать

lambda — когда функция нужна один раз, на месте, как аргумент другой функции. Типичные случаи: key= в sorted, apply() в pandas, колбэки.

def — во всех остальных случаях. Когда нужно имя, docstring, несколько выражений, обработка ошибок, повторное использование.

# Хорошо — lambda как key
sorted(data, key=lambda x: x['date'])

# Плохо — lambda с присвоением
process = lambda x: x.strip().lower().replace(' ', '_')

# Хорошо — def вместо этого
def process(x):
    """Нормализует строку для использования как идентификатор."""
    return x.strip().lower().replace(' ', '_')

Правило простое: если lambda не помещается в одну читаемую строку — используйте def.

Частые ошибки

Многострочная логика в lambda. lambda поддерживает только одно выражение. Попытка засунуть туда if/else через тернарный оператор — допустима (lambda x: 'да' if x > 0 else 'нет'), но цепочки из трёх вложенных тернарников — нечитаемы. Выносите в def.

Присвоение lambda переменной. my_func = lambda x: x + 1 — нарушение PEP 8 (E731). Линтеры ругаются. Используйте def — получите и имя, и docstring, и нормальный traceback при ошибке.

lambda в цикле без замыкания. Классическая ловушка:

# Баг — все функции вернут 4
funcs = [lambda: i for i in range(5)]
[f() for f in funcs]  # [4, 4, 4, 4, 4]

# Исправление — значение по умолчанию фиксирует i
funcs = [lambda i=i: i for i in range(5)]
[f() for f in funcs]  # [0, 1, 2, 3, 4]

Вопросы с собеседований

Что такое lambda в Python? — Анонимная функция из одного выражения. Создаётся через lambda аргументы: выражение. Результат возвращается автоматически, return не пишется. Используется как аргумент в sorted, map, filter, pandas apply.

Чем lambda отличается от def? — lambda — одно выражение, без имени, без docstring. def — полноценная функция: несколько строк, имя, docstring, обработка исключений. lambda подходит для одноразовых колбэков, def — для всего остального.

Что выведет этот код: funcs = [lambda: i for i in range(3)]; print([f() for f in funcs])?[2, 2, 2]. lambda замыкается на переменную i, а не на её значение в момент создания. К моменту вызова цикл завершён и i = 2. Исправление: lambda i=i: i.

Можно ли в lambda написать if/else? — Да, через тернарный оператор: lambda x: 'positive' if x > 0 else 'non-positive'. Полноценный if-блок с несколькими ветками — нельзя, это уже не одно выражение.

Почему не стоит присваивать lambda переменной? — PEP 8 (E731) явно запрещает это. def даёт имя в traceback, позволяет добавить docstring и легче читается. lambda без присвоения — как аргумент другой функции — нормально.

Потренировать Python-вопросы на практике можно в тренажёре Карьерника. А больше примеров вопросов — на отдельной странице.

Открыть тренажёр в Telegram — вопросы по Python, pandas, SQL и аналитике. Бесплатно.

FAQ

Можно ли в lambda использовать несколько return?

Нет. lambda содержит ровно одно выражение, и его результат возвращается автоматически. Если нужно несколько веток логики — используйте def. Тернарный оператор (a if cond else b) допустим, но не злоупотребляйте вложенностью.

lambda быстрее, чем def?

Нет. По скорости выполнения разницы нет — это один и тот же объект function под капотом. lambda экономит строки кода, но не время выполнения.

Когда в pandas лучше lambda, а когда — именованная функция?

Если логика умещается в одну строку и понятна без комментариев — lambda. Если функция содержит условия, вычисления в несколько шагов или нужна повторно — def. Пример: apply(lambda x: x.strip()) — нормально, а пять вложенных тернарников в apply — уже нет.

Чем list comprehension лучше map + lambda?

Читабельностью. [x ** 2 for x in nums] понятнее, чем list(map(lambda x: x ** 2, nums)). По скорости они сопоставимы, но comprehension — идиоматичный Python.