Лямбда-функция в Python — это функция, созданная выражением lambda аргументы: выражение: у нее нет собственного имени, тело состоит ровно из одного выражения, а его значение возвращается автоматически, без return. Чаще всего лямбду передают прямо в другую функцию — в sorted, max, map, filter — как короткое правило «что сделать с каждым элементом».
Содержание
- Три термина, которые легко спутать
- Минимальный рабочий пример
- Синтаксис: что можно указать в аргументах и теле
- Лямбда как ключ в sorted, min и max
- map, filter и reduce
- Ловушка: лямбды в цикле и позднее связывание
- Когда лямбду лучше не использовать
- Если не получилось: частые ошибки
- Выводы
- Где применяется / связь с практикой
- FAQ
Ниже — синтаксис, рабочие примеры, частые ошибки и честный ответ на вопрос, когда лямбда хуже обычного def. Все примеры проверены на Python 3.14.7, 24.09.2026.
Три термина, которые легко спутать
- lambda-выражение — сам синтаксис
lambda x: x * xв исходном коде. - объект функции — то, что это выражение создает при выполнении. Он того же типа
function, что и результатdef. - имя — переменная, которая ссылается на объект. У
defимя есть всегда, у лямбды атрибут__name__равен<lambda>, даже если объект сохранили в переменную.
Отсюда главное: лямбда — не «особый вид функций», а короткий способ создать обычную функцию с одним выражением внутри.
Минимальный рабочий пример
square = lambda x: x * x
print(square(4))
print(type(square), square.__name__)
def square_def(x):
return x * x
print(type(square_def), square_def.__name__)
Вывод:
16
<class 'function'> <lambda>
<class 'function'> square_def
Обе функции считают одно и то же и имеют один тип. Разница только в имени и в том, что внутри def можно написать несколько инструкций. Присваивать лямбду переменной, как в первой строке, допустимо для демонстрации, но в рабочем коде PEP 8 советует в таком случае писать def — об этом ниже.
Синтаксис: что можно указать в аргументах и теле
Список аргументов у лямбды такой же гибкий, как у def: значения по умолчанию, *args, именованные аргументы, **kwargs. Аргументов может не быть вовсе.
f = lambda a, b=10, *args, scale=1, **kw: (a + b + sum(args)) * scale
print(f(1), f(1, 2, 3, 4), f(1, scale=2))
hello = lambda: "hi"
print(hello())
sign = lambda x: "плюс" if x > 0 else ("ноль" if x == 0 else "минус")
print([sign(v) for v in (5, 0, -3)])
11 10 22
hi
['плюс', 'ноль', 'минус']
Условие внутри лямбды пишется условным выражением A if условие else B (это выражение, а не инструкция if) или логикой and/or. Вложенные тернарные выражения работают, но уже на двух уровнях читаются плохо.
Граница тела — «одно выражение». Что это значит на практике:
| Конструкция | В теле лямбды | Комментарий |
|---|---|---|
| арифметика, вызовы функций, срезы | да | lambda s: s.strip().lower() |
A if cond else B |
да | условное выражение |
генератор списка [... for ...] |
да | это тоже выражение |
:= (моржовый оператор) |
да, в скобках | lambda x: (y := x + 1) * y вернет 9 для x=2 |
return, if:, for:, try: |
нет | это инструкции |
присваивание y = ... |
нет | инструкция |
| аннотации типов аргументов | нет | синтаксис лямбды их не поддерживает |
Вызов print внутри лямбды разрешен — это вызов функции, то есть выражение. Лямбда вернет то, что вернул print, то есть None.
Лямбда как ключ в sorted, min и max
Самый частый и оправданный случай — аргумент key. Функция-ключ вызывается один раз для каждого элемента, и сравниваются уже ее результаты.
students = [("Оля", 91), ("Иван", 78), ("Анна", 91), ("Петр", 85)]
print(sorted(students, key=lambda s: s[1]))
print(sorted(students, key=lambda s: (-s[1], s[0])))
print(max(students, key=lambda s: s[1]))
[('Иван', 78), ('Петр', 85), ('Оля', 91), ('Анна', 91)]
[('Анна', 91), ('Оля', 91), ('Петр', 85), ('Иван', 78)]
('Оля', 91)
Что здесь видно. Первая строка сортирует по баллу по возрастанию; у Оли и Анны баллы равны, и они остались в исходном порядке — сортировка в Python устойчивая. Вторая строка возвращает кортеж: сначала балл по убыванию (минус работает только для чисел), при равенстве — имя по алфавиту. max при нескольких одинаковых максимумах возвращает первый встреченный.
Регистронезависимая сортировка строк — частая задача, где лямбда не обязательна:
words = ["banana", "apple", "Cherry"]
print(sorted(words))
print(sorted(words, key=lambda w: w.casefold()))
print(sorted(words, key=str.casefold))
['Cherry', 'apple', 'banana']
['apple', 'banana', 'Cherry']
['apple', 'banana', 'Cherry']
Без ключа заглавная C идет раньше строчных букв. Вторая и третья строки дают одинаковый результат: если лямбда лишь вызывает готовый метод или функцию, можно передать ее напрямую. Для выбора элемента кортежа или атрибута есть operator.itemgetter и operator.attrgetter: sorted(students, key=itemgetter(1)) делает то же, что первая строка примера выше.
map, filter и reduce
map применяет функцию к каждому элементу, filter оставляет элементы, для которых функция вернула истинное значение, functools.reduce сворачивает последовательность в одно значение.
from functools import reduce
nums = [1, 2, 3, 4, 5, 6]
m = map(lambda n: n * 10, nums)
print(m)
print(list(m))
print(list(m))
print(list(filter(lambda n: n % 3 == 0, nums)))
print(reduce(lambda acc, n: acc * n, nums))
print(reduce(lambda acc, n: acc + n, [], 0))
<map object at 0xf672daa27b00>
[10, 20, 30, 40, 50, 60]
[]
[3, 6]
720
0
Разбор по строкам:
- В Python 3
mapиfilterвозвращают не список, а ленивый итератор. Отсюда<map object at ...>вместо чисел (адрес в выводе будет другим). - Итератор проходится один раз: второй
list(m)дает пустой список. filterоставил числа, делящиеся на 3. Исходный список не изменился.reduceперемножил все элементы: 1·2·3·4·5·6 = 720.- Третий аргумент
reduce— начальное значение. Без него на пустом списке будетTypeError, с ним вернется 0.
Те же задачи часто короче и понятнее решаются генератором списка и встроенными функциями:
| Задача | С лямбдой | Без лямбды |
|---|---|---|
| преобразовать каждый элемент | list(map(lambda n: n * 10, nums)) |
[n * 10 for n in nums] |
| отфильтровать | list(filter(lambda n: n % 3 == 0, nums)) |
[n for n in nums if n % 3 == 0] |
| сумма | reduce(lambda a, n: a + n, nums) |
sum(nums) |
| произведение | reduce(lambda a, n: a * n, nums) |
math.prod(nums) |
| убрать «пустые» значения | filter(lambda v: v, data) |
filter(None, data) |
map с лямбдой уместен, когда функция уже есть и ее не нужно оборачивать (map(int, строки)), или когда нужен именно ленивый поток для больших данных. В остальных случаях генератор списка обычно читается лучше.
Ловушка: лямбды в цикле и позднее связывание
Лямбда запоминает не значение переменной, а саму переменную. Значение берется в момент вызова, а не в момент создания.
funcs = [lambda: i for i in range(3)]
print([g() for g in funcs])
[2, 2, 2]
Ожидали [0, 1, 2], но к моменту вызова цикл закончился, и i равно 2 для всех трех функций. Исправление — зафиксировать значение аргументом по умолчанию: он вычисляется один раз, при создании лямбды.
funcs = [lambda i=i: i for i in range(3)]
print([g() for g in funcs])
[0, 1, 2]
Альтернатива без трюка с аргументом — functools.partial. Та же ловушка касается и def внутри цикла: это свойство замыканий Python, а не только лямбд.
Когда лямбду лучше не использовать
| Критерий | lambda | def |
|---|---|---|
| тело | одно выражение | любые инструкции |
| имя в трассировке ошибки | <lambda> |
настоящее имя |
| docstring и аннотации типов | нет | есть |
try/except, циклы, несколько шагов |
нет | да |
сериализация pickle (например, для multiprocessing) |
не работает | работает для функций уровня модуля |
| передать короткое правило «на месте» | удобно | нужно отдельное определение |
Имя в трассировке — не мелочь. Вот как выглядит ошибка внутри лямбды:
div = lambda a, b: a / b
div(1, 0)
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 1, in <lambda>
ZeroDivisionError: division by zero
Когда таких лямбд в модуле десяток, строка in <lambda> мало что говорит. А попытка передать лямбду в процесс через pickle заканчивается ошибкой _pickle.PicklingError: Can't pickle <function <lambda> at ...>: it's not found as __main__.<lambda>.
Практическое правило: лямбда уместна, если она короткая, используется в одном месте и передается как аргумент. Если лямбду хочется назвать (f = lambda ...), в ней больше одного условия или ее нужно тестировать отдельно — пишите def. Это рекомендация PEP 8 и линтеров (правило E731 в pycodestyle и ruff), а не требование интерпретатора: код с присвоенной лямбдой работает.
Если не получилось: частые ошибки
SyntaxError: cannot assign to lambda. Причина — присваивание в теле: f = lambda x: y = x + 1. Интерпретатор читает это как попытку присвоить значение самой лямбде. Решение — вернуть выражение lambda x: x + 1 или перейти на def.
SyntaxError: invalid syntax у слова return или if. В теле написана инструкция: lambda x: return x, lambda x: if x > 0: x. Нужно lambda x: x и lambda x: x if x > 0 else 0. Та же ошибка, если выражение после двоеточия пропущено: lambda x:.
SyntaxError: Lambda expression parameters cannot be parenthesized. Аргументы взяты в скобки: lambda (x): x. Скобки вокруг параметров лямбды не ставятся.
TypeError: <lambda>() missing 1 required positional argument: 'b'. Лямбду с двумя аргументами вызвали с одним. Проверьте число аргументов: sorted и map с одной последовательностью передают в функцию ровно один элемент.
Вместо списка печатается <map object at ...> или <filter object ...>. Это итератор — оберните в list(). Если после первого прохода результат пустой, итератор уже исчерпан: сохраните список в переменную.
Все функции из цикла возвращают одно и то же. Это позднее связывание — добавьте аргумент по умолчанию lambda i=i: ....
Выводы
- Лямбда-функция в Python — обычный объект
function, созданный одним выражением; результат выражения возвращается безreturn. - Главное применение — короткий аргумент
keyдляsorted,min,maxи функция дляmap/filter; если лямбда лишь вызывает готовую функцию, передавайте функцию напрямую. - В Python 3
mapиfilterвозвращают одноразовые итераторы; для простых преобразований генератор списка часто понятнее. - В теле нельзя писать инструкции (
return,if:, присваивание,try), а переменные цикла подставляются в момент вызова. - Если лямбде нужно имя, docstring, обработка ошибок или несколько шагов, лучше
def.
Где применяется / связь с практикой
Освойте тему на практике
Лямбды постоянно встречаются в реальном коде: ключи сортировки отчетов, обработчики событий в GUI, apply в pandas, колбэки в тестах. Уверенно ими пользоваться помогает понимание функций как объектов, замыканий и итераторов — это основа, на которой строится дальнейшее изучение языка. Разобрать эти темы с практикой и проверкой кода преподавателем можно на курсе «Python-разработчик. Базовый уровень», а посмотреть формат обучения — на бесплатных открытых уроках Otus.
FAQ
Можно ли вызвать лямбду сразу, без переменной?
Да: (lambda x: x * 2)(5) вернет 10. В рабочем коде так почти не пишут — проще сразу записать выражение 5 * 2.
Быстрее ли лямбда, чем обычная функция?
Нет, при вызове они работают одинаково: обе создают объект того же типа function. Разница в скорости появляется из-за выбора между map с лямбдой и генератором списка, и ее стоит измерять на своих данных.
Может ли лямбда вернуть несколько значений?
Она возвращает одно значение, но им может быть кортеж: lambda x: (x, x * x) вернет пару, которую можно распаковать a, b = f(3).



