lambda-выражения в Python
В Python lambda-функция — это анонимная функция, представленная в виде одного выражения. Её можно использовать вместо обычной небольшой функции.
Для иллюстрации анонимных функций создадим пример, в котором используются обычные функции, а потом перепишем его с использованием анонимных функций.
Создадим функцию, которая принимает два аргумента:
- список слов (
words); - функцию, которую нужно применить к каждому слову из списка
words.
def edit_story(words, func):
for word in words:
print(func(word))
Теперь создадим список слов и напишем функцию, которую нужно к ним применить. В качестве слов возьмём список имён. Функция должна вывести на экран каждое имя с большой буквы и поприветствовать пользователя.
names = ['anna', 'alex', 'max', 'maria']
def greet(word):
return f'Welcome, {word.capitalize()}!'
Теперь запустим всё вместе.
def edit_story(words, func):
for word in words:
print(func(word))
names = ['anna', 'alex', 'max', 'maria']
def greet(word):
return f'Welcome, {word.capitalize()}!'
edit_story(names, greet)
# Welcome, Anna!
# Welcome, Alex!
# Welcome, Max!
# Welcome, Maria!
Функция greet() очень короткая. Мы можем заменить её lambda-выражением:
# используем уже объявленные выше edit_story и names
edit_story(names, lambda name: f'Welcome, {name.capitalize()}!')
# Welcome, Anna!
# Welcome, Alex!
# Welcome, Max!
# Welcome, Maria!
lambda-выражение имеет ноль или более аргументов, разделённых запятой, за которыми следует двоеточие (:), а за ним выражение, результат которого возвращается при вызове функции.
lambda arg1, arg2, ..., argN: выражение, использующее аргументы
В нашем примере мы передаём lambda-выражению один аргумент name.
Аргументам lambda можно присваивать значения по умолчанию:
f = lambda x=10, y=10, z=10: x + y + z
f() # 30
С точки зрения вызова, объекты функций, создаваемые выражением lambda, работают так же, как и объекты функций, создаваемые оператором def, но существует несколько отличий, которые делают lambda более удобными в специфичных сценариях:
lambda— это выражение, а не оператор. По этой причине оно может находиться в тех местах, гдеdefсинтаксически не разрешено, например, внутри спискового литерала или в аргументах вызова функции;- оператор
defсоздаёт объект функции и связывает имя с этим объектом. Выражениеlambdaвозвращает значение (новую функцию). При желании это значение можно присвоить имени; - тело
lambdaявляется одиночным выражением, а не блоком операторов. Например, мы не можем поместить в телоlambdaблок операторовifили циклfor, присваивание через=,returnи т.п.
Пример, где демонстрируется, что результат выражения lambda можно присвоить имени. Создадим две функции с одинаковым поведением.
def func(x, y, z):
return x + y + z
f = lambda x, y, z: x + y + z
func(4, 5, 6) # 15
f(4, 5, 6) # 15
Код в теле lambda следует тем же самым правилам поиска в областях видимости, что и код внутри def (правило LEGB). lambda-выражение создаёт функцию со своей локальной областью видимости. Эта область видимости работает по тем же правилам LEGB, что и область видимости обычной функции.
def farewell():
intro = "Bye bye"
return lambda name: print(f'{intro}, {name}!')
bye = farewell()
bye('Anna')
# Bye bye, Anna!
В примере выше lambda берёт переменную intro из области видимости объемлющей функции farewell.
Это поведение можно использовать для создания функций, которые сохраняют доступ к переменным из области видимости объемлющей функции.
def user_says(user_name):
return lambda phrase: print(f'{user_name} says: "{phrase}"')
maria_says = user_says("Maria")
anna_says = user_says("Anna")
maria_says("Hello everyone")
# Maria says: "Hello everyone"
anna_says("Python is awesome")
# Anna says: "Python is awesome"
В примере выше каждый вызов user_says() создаёт отдельную область видимости, поэтому функции maria_says и anna_says используют разные значения user_name.
Строго говоря, пример выше можно ещё сократить, вложив lambda внутрь lambda (да, lambda-выражения поддерживают вложенность).
user_says = lambda user_name: lambda phrase: print(f'{user_name} says: "{phrase}"')
alex_says = user_says('Alex')
alex_says('What is going on here?')
# Alex says: "What is going on here?"
Внимание! Код выше приведён исключительно для ознакомления с тёмным миром мудрёных выражений. Автор статьи не несёт ответственности за ту ругань, которая полетит в вашу сторону на код-ревью, если вы будете применять подобные конструкции.
Когда использовать lambda
Использовать lambda-выражения совершенно необязательно. Всегда можно вместо них использовать более привычный оператор def. Чаще всего именно это и требуется, так как из-за синтаксических ограничений lambda-выражения либо не работают, либо становятся малопонятными. Но в сценариях, где нужно всего лишь вставить небольшие порции исполняемого кода в места их применения, выражение lambda может сделать код проще и короче.
В целом, помните, что простое лучше сложного, а явное лучше неявного. Если в функции предполагается какая-то логика типа условных ветвлений или циклов, то полный оператор def почти наверняка будет лучше загадочного lambda-выражения. Сравните две функции, дающие одинаковый результат:
def lower_full(x, y):
if x < y:
return x
return y
lower_short = lambda x, y: x if x < y else y
print(lower_full(10, 20)) # 10
print(lower_short(10, 20)) # 10
Примечание. Ранее я упоминал, что в lambda нельзя использовать оператор if. Однако в Python условное выражение x if condition else y является не оператором, а выражением, и оно допустимо в lambda.
При умеренном использовании lambda-выражения могут быть удобными. Довольно часто анонимные функции встречаются в списке аргументов функций высшего порядка. Пример: отсортировать список пользователей по возрасту.
users = [
{'name': 'Anna', 'age': 25},
{'name': 'Alex', 'age': 28},
{'name': 'Maria', 'age': 14},
]
sorted_users = sorted(users, key=lambda user: user['age'])
for user in sorted_users:
print(user)
# {'name': 'Maria', 'age': 14}
# {'name': 'Anna', 'age': 25}
# {'name': 'Alex', 'age': 28}
Рецепт рефакторинга lambda-выражений
Если lambda-выражение читается с трудом, то настоятельно рекомендуется проследовать совету Фредрика Лундха:
- напишите комментарий, объясняющий, что делает
lambda; - внимательно изучите этот комментарий и придумайте имя, в котором заключалась бы суть изложенного в нём;
- преобразуйте
lambdaвdef, указав придуманное имя; - удалите комментарий.
Совет взят отсюда.
Источники:
- Билл Лобанович. "Простой Python. Современный стиль программирования". Питер, 2024 г.
- Марк Лутц. "Изучаем Python" 5-е изд. Диалектика, 2020 г.
- Лусиану Ромальо. "Python. К вершинам мастерства. Лаконичное и эффективное программирование". 2-е изд. ДМК, 2022 г.
- https://docs.python.org/