В этой статье вы узнаете о том, что такое лямбда-функции в Python. На самом деле, если вы знаете, что такое функции и умеете с ними работать, то знаете и что такое лямбда.
Лямбда-функция в Python — это просто функция Python. Но это некий особенный тип с ограниченными возможностями. Если есть желание погрузиться глубже и узнать больше, то эта статья целиком посвящена lambda
.
Что такое лямбда в Python?
Прежде чем переходить как разбору понятия лямбда в Python, попробуем понять, чем является обычная функция Python на более глубоком уровне.
Для этого потребуется немного поменять направление мышление. Как вы знаете, все в Python является объектом.
Например, когда мы запускаем эту простейшую строку кода
x = 5
Создается объект Python типа int
, который сохраняет значение 5. x
же является символом, который ссылается на объект.
Теперь проверим тип x
и адрес, на которой он ссылается. Это можно сделать с помощью встроенных функций type
и id
.
>>> type(x)
<class 'int'>
>>> id(x)
4308964832
В итоге x
ссылается на объект типа int
, а расположен он по адресу, который вернула функция id
.
Просто и понятно.
А что происходит при определении вот такой функции:
>>> def f(x):
... return x * x
...
Повторим упражнение и узнаем type
и id
объекта f
.
>>> def f(x):
... return x * x
...
>>> type(f)
<class 'function'>
>>> id(f)
4316798080
Оказывается, в Python есть класс function
, а только что определенная функция f
— это его экземпляр. Так же как x
был экземпляром класса integer
. Другими словами, о функциях можно думать как о переменных. Разница лишь в том, что переменные хранят данные, а функции — код.
Это же значит, что функции можно передать в качестве аргументов другим функциям или даже использовать их как тип возвращаемого значения.
Рассмотрим простой пример, где функция f
передается другой функции.
def f(x):
return x * x
def modify_list(L, fn):
for idx, v in enumerate(L):
L[idx] = fn(v)
L = [1, 3, 2]
modify_list(L, f)
print(L)
#вывод: [1, 9, 4]
Попробуйте разобраться самостоятельно с тем, что делает этот код, прежде чем читать дальше.
Итак, modify_list
— это функция, которая принимает список L
и функцию fn
в качестве аргументов. Затем она перебирает список элемент за элементом и применяет функцию к каждому из них.
Это общий способ изменения объектов списка, ведь он позволяет передать функцию, которая займется преобразованием. Так, если передать modify_list
функцию f
, то результатом станет список, где все значения будут возведены в квадрат.
Но можно передать и любую другую, которая изменит оригинальный список другим способом. Это очень мощный инструмент.
Теперь, когда с основами разобрались, стоит перейти к лямбда. Лямбда в Python — это просто еще один способ определения функции. Вот базовый синтаксис лямбда-функции в Python:
lambda arguments: expression
Лямбда принимает любое количество аргументов (или ни одного), но состоит из одного выражения. Возвращаемое значение — значение, которому присвоена функция. Например, если нужно определить функцию f
из примера выше, то это можно сделать вот так:
>>> f = lambda x: x * x
>>> type(f)
<class 'function'>
Но возникает вопрос: а зачем нужны лямбда-функции, если их можно объявлять традиционным образом? Но на самом деле, они полезны лишь в том случае, когда нужна одноразовая функция. Такие функции еще называют анонимными. И, как вы увидите дальше, есть масса ситуаций, где они оказываются нужны.
Лямбда с несколькими аргументами
Определить лямбда-функцию с одним аргументом не составляет труда.
>>> f = lambda x: x * x
>>> f(5)
25
А если их должно быть несколько, то достаточно лишь разделить значения запятыми. Предположим, что нужна функция, которая берет два числовых аргумента и возвращает их произведение.
>>> f = lambda x, y: x * y
>>> f(5, 2)
10
Отлично! А как насчет лямбда-функции без аргументов?
Лямбда-функция без аргументов
Допустим, нужно создать функцию без аргументов, которая бы возвращала True
. Этого можно добиться с помощью следующего кода.
>>> f = lambda: True
>>> f()
True
Несколько лямбда-функций
В определенный момент возникнет вопрос: а можно ли иметь лямбда-функцию из нескольких строк.
Ответ однозначен: нет.
Лямбда-функции в Python всегда принимают только одно выражение. Если же их несколько, то лучше создать обычную функцию.
Примеры лямбда-функций
Теперь рассмотрим самые распространенные примеры использования лямбда-функций.
Лямбда-функция и map
Распространенная операция со списками в Python — применение операции к каждому элементу.
map()
— это встроенная функция Python, принимающая в качестве аргумента функцию и последовательность. Она работает так, что применяет переданную функцию к каждому элементу.
Предположим, есть список целых чисел, которые нужно возвести в квадрат с помощью map
.
>>> L = [1, 2, 3, 4]
>>> list(map(lambda x: x**2, L))
[1, 4, 9, 16]
Обратите внимание на то, что в Python3 функция map возвращает объект Map
, а в Python2 — список.
Так, вместо определения функции и передачи ее в map в качестве аргумента, можно просто использовать лямбда для быстрого определения ее прямо внутри. В этом есть смысл, если упомянутая функция больше не будет использоваться в коде.
Вот еще один пример.
Лямбда-функция и filter
filter()
— это еще одна встроенная функция, которая фильтрует последовательность итерируемого объекта.
Другими словами, функция filter
отфильтровывает некоторые элементы итерируемого объекта (например, списка) на основе какого-то критерия. Критерий определяется за счет передачи функции в качестве аргумента. Она же применяется к каждому элементу объекта.
Если возвращаемое значение — True
, элемент остается. В противном случае — отклоняется. Определим, например, простую функцию, которая возвращает True
для четных чисел и False
— для нечетных:
def even_fn(x):
if x % 2 == 0:
return True
return False
print(list(filter(even_fn, [1, 3, 2, 5, 20, 21])))
#вывод: [2, 20]
С лямбда-функциями это все можно сделать максимально сжато. Код выше можно преобразовать в такой, написанный в одну строку.
print(list(filter(lambda x: x % 2 == 0, [1, 3, 2, 5, 20, 21])))
И в этом сила лямбда-функций.
Лямбда-функция и сортировка списков
Сортировка списка — базовая операция в Python. Если речь идет о списке чисел или строк, то процесс максимально простой. Подойдут встроенные функции sort
и sorted
.
Но иногда имеется список кастомных объектов, сортировать которые нужно на основе значений одного из полей. В таком случае можно передать параметр key
в sort
или sorted
. Он и будет являться функцией.
Функция применяется ко всем элементам объекта, а возвращаемое значение — то, на основе чего выполнится сортировка. Рассмотрим пример. Есть класс Employee
.
class Employee:
def __init__(self, name, age):
self.name = name
self.age = age
Теперь создадим экземпляры этого класса и добавим их в список.
Alex = Employee('Alex', 20)
Amanda = Employee('Amanda', 30)
David = Employee('David', 15)
L = [Alex, Amanda, David]
Предположим, что мы хотим отсортировать его на основе поля age
сотрудников. Вот что нужно сделать для этого:
L.sort(key=lambda x: x.age)
print([item.name for item in L])
# вывод: ['David', 'Alex', 'Amanda']
Лямбда-выражение было использовано в качестве параметра key
вместо отдельного ее определения и затем передачи в функцию sort
.
Пара слов о выражениях и инструкциях
Как уже упоминалось, лямбда могут иметь только одно выражение (expression) в теле.
Обратите внимание, что речь идет не об инструкции (statement).
Выражение и инструкции — две разные вещи, в которых часто путаются. В программировании инструкцией является строка кода, выполняющая что-то, но не генерирующая значение.
Например, инструкция if
или циклы for
и while
являются примерами инструкций. Заменить инструкцию на значение попросту невозможно.
А вот выражения — это значения. Запросто можно заменить все выражения в программе на значения, и программа продолжит работать корректно.
Например:
3 + 5
— выражение со значением 810 > 5
— выражение со значением TrueTrue and (5 < 3)
— выражение со значением False
Тело лямбда-функции должно являться выражением, поскольку его значение будет тем, что она вернет. Обязательно запомните это для работы с лямбда-функциями в будущем.