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

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

Итак… Что такое лямбда-функция?

В Python (и многих других языках) лямбда-функция — это просто анонимная функция, содержащая только одно выражение.

Простой пример — лямбда-функция, используемая для возведения x в степень 2.

lambda x: x ** 2

Здесь у нас есть ключевое слово lambda для обозначения того, что это лямбда-функция, за которым следует аргумент лямбда x. Одиночное лямбда-выражение находится справа от двоеточия. Результатом выражения будет возвращаемое значение лямбда-функции.

Более практичный пример — передача лямбда-функции в качестве функции фильтрации во встроенную функцию filter().

# Create a list of all even numbers between 0-10.
filtered = [n for n in filter(lambda x: x % 2 == 0, range(0,11))]
print(filtered)
>>> [0, 2, 4, 6, 8, 10]

В этом примере лямбда-функция вызывается функцией filter, которой она передается. Затем каждый элемент в итерируемом range(0,11) передается в аргумент лямбда-выражения x, лямбда-выражение оценивает, является ли число нечетным или четным, и соответственно возвращает true или false. Только значения, оцененные как истинные в лямбда-функции, затем включаются в результирующую итерацию, созданную функцией filter().

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

def filter_even(x):
    return x % 2 == 0
# Create a list of all even numbers between 0-10.
filtered = [n for n in filter(filter_even, range(0,11))]
print(filtered)

Представление?

Учитывая совершенно другой синтаксис по сравнению с обычным определением функции, можно было бы подумать, что среда выполнения Python выполняет лямбда-функции по-другому, что приводит к некоторому изменению производительности.

Это не так, как видно из приведенного ниже диассемблированного байт-кода Python, единственное отличие состоит в том, что стандартная функция Python имеет имя, в котором лямбда-функция называется просто lambda.

print(dis("def filter_even(x): return x % 2 == 0"))
# Standard Python function bytecode
Disassembly of <code object filter_even at 0x101b0bea0, file "<dis>", line 1>:
  1           0 LOAD_FAST                0 (x)
              2 LOAD_CONST               1 (2)
              4 BINARY_MODULO
              6 LOAD_CONST               2 (0)
              8 COMPARE_OP               2 (==)
             10 RETURN_VALUE
print(dis("lambda x: x % 2 == 0"))
# Lambda function bytecode
Disassembly of <code object <lambda> at 0x10b59cd40, file "<dis>", line 1>:
  1           0 LOAD_FAST                0 (x)
              2 LOAD_CONST               1 (2)
              4 BINARY_MODULO
              6 LOAD_CONST               2 (0)
              8 COMPARE_OP               2 (==)
             10 RETURN_VALUE

Вывод

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

Однако есть несколько недостатков, связанных с ними.

  • Незнакомый синтаксис.
  • Не подлежит тестированию.
  • Невозможно предоставить строку документации.
  • Трудно понять трассировку из-за лямбда-функций, не имеющих определенного имени.

Поскольку недостатки в значительной степени перевешивают преимущества, я бы, вероятно, воздержался от лямбда-функций во всем, кроме простых функций, предоставляемых в качестве аргументов для таких функций, как sorted(), map() и filter().