Анонимные (lambda) функции

Курс по Python: https://stepik.org/course/100707

Смотреть материал на YouTube | RuTube

Это занятие будет посвящено, так называемым, анонимным или, их еще называют, lambda функциям. Что это за функции и почему их называют анонимными? Сейчас вы все узнаете!

Лямбда функция определяется по очень простому синтаксису:

lambda param_1, param_2, …: команда

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

lambda a, b: a + b

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

s = lambda a, b: a + b

И уже через нее вызывать саму функцию:

s(1, 2)

В чем особенность такого определения функции? Зачем ее придумали и почему бы не пользоваться обычными функциями? У нее есть одно принципиальное отличие от ранее рассматриваемых нами функций – она может быть записана как элемент любой конструкции языка Python. Например, прямо как элемент списка:

a = [4, 5, lambda: print("lambda"), 7, 8]

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

a[2]

то увидим ссылку на объект-функцию. И, как мы уже знаем, чтобы ее запустить на выполнение нужно прописать оператор – круглые скобки:

a[2]()

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

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

lst = [5, 3, 0, -6, 8, 10, 1]

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

def get_filter(a, filter=None):
    if filter is None:
        return a
 
    res = []
    for x in a:
        if filter(x):
            res.append(x)
 
    return res

Здесь второй параметр filter – это ссылка на другую функцию, которая будет отбирать значения из списка lst. Если вызвать ее только с первым аргументом:

lst = [5, 3, 0, -6, 8, 10, 1]
r = get_filter(lst)
print(r)

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

r = get_filter(lst, lambda p: p % 2 == 0)

то возвратится новый список, состоящий только из четных значений. Как это произошло? В этом примере второй параметр filter функции get_filter стал ссылаться на лямбда-функцию. Эта функция возвращает True для четных значений и False – для нечетных. Соответственно, в цикле при переборе элементов списка, условие будет срабатывать только для четных значений и только они будут добавляться в список res. Видите, как удобно и наглядно можно использовать лямбда-функции в программировании? Если бы их не существовало, нам бы пришлось объявлять отдельную функцию:

def even(p):
    return p % 2 == 0

А, затем, передавать ссылку на нее:

r = get_filter(lst, even)

Согласитесь, это несколько более трудоемкий и менее удобный вариант? Мало того, если нам понадобится быстро изменить фильтр, то достаточно поправить реализацию анонимной функции, например, для выделения только положительных чисел:

r = get_filter(lst, lambda p: p > 0)

Быстро и просто! В этом одно из удобств этих анонимных функций – их можно сразу прописать в нужном месте программы.

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

lambda a: 
    print(a)

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

lambda a: a = 1

Это также вызовет синтаксическую ошибку. Здесь мы можем лишь создавать новый объект на основе входных параметров (или глобальных, общих переменных программы):

s = lambda a: a + 1
s(1)
p = lambda: "hello python"
p()

либо просто возвращать ссылки на уже существующие объекты:

lambda a: a

На этом мы завершим текущее занятие. Для закрепления материала пройдите практические задания и переходите к следующему уроку.

Курс по Python: https://stepik.org/course/100707

Видео по теме