Немного про лямбда-функции в Python
Что это такое?
Lambda или анонимные функции - это по сути небольшие функции без имени, написанные в одну строку.
Для их объявления нам не нужно следовать классической схеме - указывать литерал def и имя будущей функции. Нам достаточно следовать такой конструкции:
lambda arguments: expression
Это и есть весь синтаксис лямбда-функций.
- Аргументов может быть несколько
- Выражение может быть только одно
- Выражение должно быть написано в одну строку
- Лямбда-функция всегда возвращает значение
Как и когда использовать?
Чаще всего, лямбда-функции используют в нескольких случаях:
Лямбда-функция как аргумент в других функциях
Очень удобно применять лямбда-функции при работе с map() и filter().
Допустим, нам нужно преобразовать список. Здесь нам поможет функция map(), которая применит лямбда-функцию ко всем элементам списка:
list_1 = ["one", "two", "three"] new_list = list(map(lambda x: "new_" + x, list_1)) print(new_list) >>> ['new_one', 'new_two', 'new_three']
Лямбда помогает нам задать нечто вроде правила, по которому будет обрабатываться объект. В нашем примере мы добавили префикс к каждому слову в списке.
Эту же операцию можно решить и с помощью list comprehension (списочных выражений):
new_list = ["new_" + x for x in list_1]
Теперь рассмотрим простой пример с фильтрацией:
list_1 = ["one", "two", "three"] new_list = list(filter(lambda x: len(x) <= 3, list_1)) print(new_list) >>> ['one', 'two']
Мы применили функцию filter() и получили новый список с элементами, у которых количество символов меньше или равно 3.
Эту операцию тоже можно решить с помощью list comprehension:
new_list = [x for x in list_1 if len(x) <= 3]
Рассмотрим еще 1 применение при сортировке по ключу. Он будет интереснее, так как будем работать с объектами посложнее:
# Создадаем класс с атрибутами экземпляра: имя, возраст и порода
class Cat:
def __init__(self, name: str, age: int, breed: str) -> None:
self.name = name
self.age = age
self.breed = breed
# Переопределяем магический метод __repr__, чтобы при печати экземпляров выводился сразу человекочитаемый текст
def __repr__(self) -> str:
return f"<<Cat {self.name}, {self.breed}, {self.age} years old>>"
# Создаем экземпляры класса Cat
cat_1 = Cat(name="Mars", age=7, breed="British Shorthair")
cat_2 = Cat(name="Oleg", age=1, breed="Devon Rex")
cat_3 = Cat(name="Bublik", age=2, breed="Russian Blue")
# Создаем неотсортированный список с питомцами
list_of_cats = [cat_3, cat_1, cat_2]
# Сортируем список по имени, возрасту и породе
name_sorted = sorted(list_of_cats, key=lambda x: x.name)
age_sorted = sorted(list_of_cats, key=lambda x: x.age)
breed_sorted = sorted(list_of_cats, key=lambda x: x.breed)
print(name_sorted, age_sorted, breed_sorted, sep="\n")
[<<Cat Bublik, Russian Blue, 2 years old>>, <<Cat Mars, British Shorthair, 7 years old>>, <<Cat Oleg, Devon Rex, 1 years old>>]
[<<Cat Oleg, Devon Rex, 1 years old>>, <<Cat Bublik, Russian Blue, 2 years old>>, <<Cat Mars, British Shorthair, 7 years old>>]
[<<Cat Mars, British Shorthair, 7 years old>>, <<Cat Oleg, Devon Rex, 1 years old>>, <<Cat Bublik, Russian Blue, 2 years old>>]Выглядит просто, читаемо и эффективно.
Лямбда-функции и замыкания
Для начала пара слов о замыканиях.
Замыкание — это вложенная функция, которая имеет доступ к переменным внешней функции даже после закрытия этой самой внешней функции.
С помощью замыканий можно сохранять значения и состояния между вызовами функций.
Может звучать немного запутанно, но пока не будем вдаваться в детальное объяснение и рассмотрим пример. Более подробно обсудим замыкания в будущих статьях. Ну а после примера, в любом случае, станет понятнее.
def multiplier(x):
return lambda y: x * y
multiply_by_2 = multiplier(x=2)
multiply_by_5 = multiplier(x=5)
print(multiply_by_2(y=2))
print(multiply_by_5(y=2))
>>> 4
>>> 10- Мы объявили функцию
multiplierс параметром x, внутри которой возвращается вложенная лямбда-функция, которая умножаетxнаy. - Далее мы по сути делаем из переменных
multiply_by_2иmultiply_by_5функции-перемножители, которые запоминают значение переменнойx, которое будет доступно нам всегда. - Затем вызываем уже внутреннюю лямбда-функцию, передавая перемножителю параметр
y. - В результате мы получаем произведение двух чисел - значений переменных
xиy.
Таким образом, замыкания помогают на лету создавать функции, при этом частично изолировав логику выполнения (как мы видели на примере с конкретными перемножителями).
В этой статье мы окунулись в сферу применения лямбда-функций и затронули пару таких тем как функции высшего порядка и замыкания.
Зачастую можно обойтись и без лямбда-функций, но в определенных моментах они могут добавить удобства и чистоты в код.