В этой статье вы подробнее изучите анонимные функции, так же называемые "лямбда-функции". Давайте разберемся, что это такое, каков их синтаксис и как их использовать ( с примерами).

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

Лямбда-функция имеет следующий синтаксис.

Lambda аргументы: выражение

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

1.1. Пример лямбда-функции.

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

double = lambda x: x*2
print(double(5))

Вывод:

10

В вышеуказанном коде lambda x: x*2 — это лямбда-функция. Здесь x — это аргумент, а x*2 — это выражение, которое вычисляется и возвращается.

Эта функция безымянная. Она возвращает функциональный объект с идентификатором double. Сейчас мы можем считать её обычной функцией.

Инструкция:

double = lambda x: x*2

Эквивалентна:

def double(x):
		return x * 2
  • Эта функция может иметь любое количество аргументов, но вычисляет и возвращает только одно значение

  • Лямбда-функции применимы везде, где требуются объекты-функции 

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

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

2. Различие между обычной функцией и лямбда-функцией

Рассмотрим пример и попробуем понять различие между определением (Def) для обычной функции и lambda-функции. Этот код возвращает заданное значение, возведенное в куб:

def defined_cube(y):
    return y*y*y


lambda_cube = lambda y: y*y*y
print(defined_cube(2))
print(lambda_cube(2))

Вывод:

8
8

Как показано в примере выше, обе представленные функции, defined_cube() и  lambda_cube(), ведут себя одинаково, как и предполагалось.

Разберем вышеуказанный пример подробнее:

  • Без использования лямбды: Здесь обе функции возвращают заданное значение, возведенное в куб. Но при использовании def, нам пришлось определить функцию с именем и defined_cube() дать ей входную величину.  После выполнения нам также понадобилось возвратить результат, из того места, откуда была вызвана функция, и мы сделали это, используя ключевое слово return.

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

3. Лямбда-функции и функции высшего порядка

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

В Python мы часто используем их как аргумент функции высшего порядка (функции, которая принимает другие функции в качестве аргументов).  Лямбда-функции используют вместе с такими встроенными функциями как filter()map(),reduce() и др.

Давайте рассмотрим еще несколько распространенных вариантов использования лямбда-функций.

3.1. Пример с filter()

Функция filter() в Python принимает в качестве аргументов функцию и список .

Функция вызывается со всеми элементами в списке, и в результате возвращается новый список, содержащий элементы, для которых функция результирует в True.

Вот пример использования функции filter() для отбора четных чисел из списка.

my_list = [1, 3, 4, 6, 10, 11, 15, 12, 14]
new_list = list(filter(lambda x: (x%2 == 0) , my_list))
print(new_list)

Вывод:

[4, 6, 10, 12, 14]

3.2. Пример с map()

Функция map() принимает в качестве аргументов функцию и список.

Функция вызывается со всеми элементами в списке, и в результате возвращается новый список, содержащий элементы, возвращенные данной функцией для каждого исходного элемента.

Ниже пример использования функции map() для удвоения всех элементов списка.

current_list = [1, 3, 4, 6, 10, 11, 15, 12, 14]
new_list = list(map(lambda x: x*2 , current_list))
print(new_list)
[2, 6, 8, 12, 20, 22, 30, 24, 28]

Вывод:

3.3. Пример с reduce()

Функция reduce() принимает в качестве аргументов функцию и список. Функция вызывается с помощью лямбда-функции и итерируемого объекта  и возвращается новый уменьшенный результат. Так выполняется повторяющаяся операцию над парами итерируемых объектов. Функция reduce() входит в состав модуля functools.

from functools import reduce


current_list = [5, 15, 20, 30, 50, 55, 75, 60, 70]
summa = reduce((lambda x, y: x + y), current_list)
print(summa)

Вывод:

380

Здесь результаты предыдущих двух элементов суммируются со  следующим элементом, и это продолжается до конца списка, вот так:

5+15+20+30+50+55+75+60+70

4. Лямбда и  списковое включение

В этом примере мы будем использовать лямбда-функцию со списковым включением и лямбда-функцию с циклом for. Мы выведем на экран  таблицу из 10 элементов.

tables = [lambda x = x: x*10 for x in range(1, 11)]
for table in tables:
    print(table())

Вывод:

10
20
30
40
50
60
70
80
90
100

5. Лямбда и условные операторы

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

Например, есть две цифры, и вы должны определить, какая из них представляет наибольшее число.

max_number = lambda a, b: a if a > b else b
print(max_number(3, 5))

Вывод:

5

Этот метод позволяет вам добавлять условия в лямбда-функции.

6. Лямбда и множественные операторы

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

current_list = [[10,6,9],[0, 14, 16, 80],[8, 12, 30, 44]]
sorted_list = lambda x: (sorted(i) for i in x)
second_largest = lambda x, func: [y[len(y)-2] for y in func(x)]
result = second_largest(current_list, sorted_list)
print(result)

Вывод:

[9, 16, 30]

В предыдущем примере, мы создали лямбда-функцию, которая сортирует каждый вложенный список в заданном списке. Затем этот список проходит как параметр для второй лямбда-функции, которая возвращает элемент n-2 из отсортированного списка, где  n — длина вложенного списка.

Заключение

Теперь вы знаете как использовать в Python lambda-функции и можете:

  • Писать и использовать лямбда-функции.

  • Рационально выбирать между обычными и лямбда-функциями в Python.

  • Использовать лямбды с функциями высшего порядка или ключевыми функциями.

  • Использовать лямбды с абстракциями списков.

  • Добавлять условия к лямбда-функциям.

Комментарии (9)


  1. alexyr
    30.06.2022 10:13
    +4

    #6 это жесть. Квадратное колесо едет плохо, но если мы возьмём 2 таких колеса вместе, то станет чуток лучше. Питон это не про краткость, а про читаемость. Я понимаю что это синтетические примеры... Но скорость разработки, основное преимущество питона, нивелируется такими конструкциями! Попробуй потом пойми, что имел ввиду автор...


  1. BasicWolf
    30.06.2022 10:17
    +3

    Питер, вам не стыдно? Давайте ещё статью о том как объявлять переменные опубликуем на Хабре. Более того, в статье даются откровенно вредные советы.

    Из коротенького параграфа документации посвящённому лямбда-функциям:

    Small anonymous functions can be created with the lambda keyword.  Semantically, they are just syntactic sugar for a normal function definition.

    Код вроде этого в корне не верен:

    sorted_list = lambda x: (sorted(i) for i in x)
    second_largest = lambda x, func: [y[len(y)-2] for y in func(x)]


    1. sukhe
      30.06.2022 11:56
      +4

      Давайте ещё статью о том как объявлять переменные опубликуем на Хабре.

      Гм... Интересная идея. Особенно, если не ограничиваться Питоном и немножно "залезть в потроха". Как хранится, как передаётся, выделение памяти, сборщики мусора... Тут можно копать и копать.


    1. smind
      03.07.2022 02:24

      а мне стать в самый раз, отправил сыну, написано очень доступно


  1. Sklott
    30.06.2022 12:36
    +1

    а кто-нибудь может сказать зачем нужна вот эта жесть:

    tables = [lambda x = x: x*10 for x in range(1, 11)]
    for table in tables:
        print(table())

    если проще написать без всяких лямбд:

    tables = [x*10 for x in range(1, 11)]
    for table in tables:
        print(table)


    1. HuanSebastyan
      30.06.2022 15:03


      Ну, тут наверно просто хотели показать идею “ленивого вычисления”(или как там правильно перевести lazy evaluation?) . 

      В первом случае первая строчка создает только массив лямбд, а конкретные значения получаются позже, когда мы эти лямбды выполняем: table().


      1. Sklott
        30.06.2022 16:43

        Ну как-бы наверно, да. Если бы не одно но. В питоне лямбды настолько кастрированные, что в 99% случаев нет никакого смысла вычислять их лениво...


        1. funca
          01.07.2022 00:49

          Тут на самом деле есть неочевидная засада. Если вместо:

          tables = [lambda x = x: x*10 for x in range(1, 11)]

          Написать лямбду без параметров (нам ведь они потом не нужны):

          tables = [lambda: x*10 for x in range(1, 11)]

          то получится ерунда.


  1. souls_arch
    02.07.2022 23:37

    Лямбда класс/интерфейс я понимаю. Джавист. Но вот до лямбда функций си# пайтона, так и не догнал. Науя? Чтобы не обьявить пару лишних переменных внутри метода? Может я - дурак. Но это все анти паттерн ООП. Переписывыл такие методы с шарпа на джаву. Надо было в метод вложить метод с кучей параметров и дерево безгранично в итоге.

    Про функционалку и стримы в джава ничего против не имею. Я лишь про вопиющие приемы конкретно пайиона и шарпа