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]) # 10lambda 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.