Лямбда-функции в Python

| Python

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

Ключевое слово lambda в Python предоставляет шорткат для объявления небольших анонимных функций. Лямбда-функции ведут себя подобно обычным функциям, объявленные с ключевым словом def. Они могут использоваться, когда требуются объекты класса функция.

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

>>> add = lambda x, y: x + y
>>> add(5, 3)
8

Теперь, объявим ту же функцию сложения с ключевым словом def:

>>> def add(x, y):
...     return x + y
>>> add(5, 3)
8

Возникает разумный вопрос – для чего нужны лямбда-функции, если это всего лишь более краткая версия объявления функций с def?

Рассмотрим следующий пример:

>>> (lambda x, y: x + y)(5, 3)
8

Как работает этот код? Использована лямбда для определения однострочной функции «сложения», а затем сразу вызвали её с аргументами 5 и 3.

Понятно, что лямбда-выражение lambda x, y: x + y совпадает с объявлением функции с def, только она написана в строку. Разница в том, что не произведена привязка её к имени, например add. Было сформулировано выражение, которое нужно вычислить, а затем сразу же вызвали её, подобно классической функции.

Существует еще одна синтаксическая разница между lambdas и регулярными определениями функций: лямбда-функции ограничены одним выражением. Это означает, что лямбда-функция не может использовать операторы или аннотации, даже оператор return.

Как же возвращается значения из лямбд? Выполнение лямбда-функции вычисляет её выражение и затем автоматически возвращает результат. Поэтому всегда есть неявный оператор return. Вот почему некоторые люди относятся к лямбдам как функциям одного выражения.

Когда нужно использовать лямбды?

Технически, когда нужно определить объект типа функции, можно использовать лямбда выражения. И поскольку лямбда выражения могут быть анонимными, вам даже не нужно назначать ей имя.

Это позволяет создавать удобный и компактный шорткат для определения функции в Python. Самый часто используемый случай использования лямбд заключается в написании коротких и сжатых key функций для сортировки итераций:

>>> sorted(range(-5, 6), key=lambda x: x ** 2)
[0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5]

Подобно обычным вложенным функциям, лямбды также работают как лексические замыкания.

Что такое лексическое замыкание? Это причудливое имя для функции, которая запоминает значения из охватывающей области видимости переменных, даже если поток программы больше не находится в этой области. Далее представлен пример (достаточно академический), поясняющий идею:

>>> def make_adder(n):
...     return lambda x: x + n

>>> plus_3 = make_adder(3)
>>> plus_5 = make_adder(5)

>>> plus_3(4)
7
>>> plus_5(4)
9

В приведенном выше примере x + n lambda все еще может получить доступ к значению n, даже если оно определено в функции make_adder (охватывающая область).

Иногда использование лямбда-функции вместо вложенной функции, объявленной с помощью def, может более четко выражать намерение. Но это не редко встречающийся кейс, по крайней мере, в том виде кода, который обычно используют.

Когда не стоит их использовать?

Лямбда-функции должны использоваться экономно и с чрезвычайной осторожностью. Если вы соблазняетесь использовать лямбда, потратьте несколько секунд (или минут), чтобы подумать, действительно ли это самый чистый и удобный способ достижения желаемого результата.

Например, делать что-то вроде этого, чтобы распечатать две строки кода, просто глупо. Конечно, технически это работает, и это достаточно хороший «трюк», но резко снижет читаемость и поддерживаемость кода.

# Не делайте так! Антипаттерн
>>> class Car:
...     rev = lambda self: print('Wroom!')
...     crash = lambda self: print('Boom!')

>>> my_car = Car()
>>> my_car.crash()
'Boom!'

Аналогичное отношение к сложным конструкциям map() или filter(), использующим лямбды. Как правило, гораздо понятнее воспользоваться списком или выражением генератора:

# Не далаёте так. Антипаттерн.
>>> list(filter(lambda x: x % 2 == 0, range(16)))
[0, 2, 4, 6, 8, 10, 12, 14]

# Предпочтительный вариант 
>>> [x for x in range(16) if x % 2 == 0]
[0, 2, 4, 6, 8, 10, 12, 14]

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

Рекомендации по применению лямбда-функций.

  • Лямбда-функции - это функции в одно выражение, которые необязательно связаны с именем.
  • Лямбда-функции не могут использовать операторы Python и всегда содержат неявный оператор return.
  • Всегда спрашивайте себя: может лучше воспользоваться регулярной (именованной) функцией или выражением в виде списка/генератора для большей ясности?