Немного про лямбда-функции в 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
.
Таким образом, замыкания помогают на лету создавать функции, при этом частично изолировав логику выполнения (как мы видели на примере с конкретными перемножителями).
В этой статье мы окунулись в сферу применения лямбда-функций и затронули пару таких тем как функции высшего порядка и замыкания.
Зачастую можно обойтись и без лямбда-функций, но в определенных моментах они могут добавить удобства и чистоты в код.