Функции как значения и lambda
Теория
Функция в Python — такое же значение, как число или строка: её можно положить в переменную, в список или словарь, передать в другую функцию и вернуть из функции. Имя без скобок (get_price) — это сама функция, со скобками (get_price(p)) — результат её вызова. На этой разнице держится много инструментов: sorted, min и max принимают параметр key — функцию, которая для каждого элемента говорит, по чему его сравнивать.
Для коротких одноразовых функций есть lambda — функция без имени, записанная одним выражением: lambda p: p["price"]. Её используют прямо в месте передачи, чаще всего как key. Встроенные map и filter тоже принимают функцию, но в Python их обычно заменяют comprehension — он читается проще.
Наглядно
Таблица 1. Функция как значение на списке товаров products.
| Запись | Что это | Результат |
|---|---|---|
get_price |
сама функция | объект функции |
get_price(p) |
вызов функции | цена товара p |
sorted(products, key=get_price) |
передача функции | товары по возрастанию цены |
sorted(products, key=lambda p: p["price"]) |
то же через lambda | товары по возрастанию цены |
max(products, key=lambda p: p["price"]) |
key у max |
товар с максимальной ценой (не цена) |
sorted(products, key=lambda p: (p["category_id"], -p["price"])) |
ключ-кортеж | по категории, внутри — от дорогих к дешёвым |
Таблица 2. lambda и def.
lambda |
def |
|
|---|---|---|
| Имя | нет (анонимная) | есть |
| Тело | одно выражение, результат возвращается сам | любые инструкции, нужен return |
| Где уместна | короткий key, одноразовая функция |
всё остальное, особенно логика, которую нужно тестировать |
На практике
Задача: сортировать каталог по разным полям, находить самый дешёвый и дорогой товар и выбирать обработчик по статусу заказа.
Шаг 1. Сохраняем функцию в переменной
Функцию можно присвоить другому имени и вызвать через него:
def format_price(price): return f"{price} ₽" show = format_price print(show(1499)) print(type(show))
Результат:
1499 ₽ <class 'function'>
Шаг 2. Передаём функцию в sorted
key — функция, которая для каждого товара возвращает значение для сравнения:
products = [
{"name": "Клавиатура", "price": 5990, "category_id": 3},
{"name": "Мышь", "price": 1499, "category_id": 3},
{"name": "Коврик", "price": 490, "category_id": 5},
]
def get_price(product):
return product["price"]
cheap_first = sorted(products, key=get_price)
print([p["name"] for p in cheap_first])Результат:
['Коврик', 'Мышь', 'Клавиатура']
Передаём get_price без скобок — sorted сам вызовет её для каждого товара.
Шаг 3. Пишем то же через lambda
Для одноразового ключа отдельная функция не нужна:
by_price_desc = sorted(products, key=lambda p: p["price"], reverse=True) print([p["name"] for p in by_price_desc])
Результат:
['Клавиатура', 'Мышь', 'Коврик']
Шаг 4. Находим товар через min и max
С key функции min и max возвращают элемент, а не значение ключа:
cheapest = min(products, key=lambda p: p["price"]) print(cheapest["name"], cheapest["price"]) print(max(p["price"] for p in products))
Результат:
Коврик 490 5990
Вторая строка — максимум из цен: так получается число, а не товар.
Шаг 5. Сортируем по нескольким полям
Ключ-кортеж сравнивается по первому полю, при равенстве — по второму. Минус перед числом даёт обратный порядок для этого поля:
ordered = sorted(products, key=lambda p: (p["category_id"], -p["price"])) print([(p["category_id"], p["name"]) for p in ordered])
Результат:
[(3, 'Клавиатура'), (3, 'Мышь'), (5, 'Коврик')]
Шаг 6. Используем map и filter
map применяет функцию к каждому элементу, filter оставляет элементы, для которых функция истинна. Обе возвращают ленивый объект — для списка нужен list():
names = map(lambda p: p["name"], products) print(type(names)) print(list(names)) print(list(filter(lambda p: p["price"] < 2000, products))[0]["name"]) print([p["name"] for p in products if p["price"] < 2000])
Результат:
<class 'map'> ['Клавиатура', 'Мышь', 'Коврик'] Мышь ['Мышь', 'Коврик']
map вернул не список, а объект map, который выдаёт значения по одному. Последняя строка — то же через comprehension: обычно его и выбирают.
Шаг 7. Выбираем функцию по ключу
Словарь функций — простой способ выбрать обработчик по статусу без длинной цепочки if:
def notify_paid(order_id): return f"Заказ №{order_id} оплачен" def notify_shipped(order_id): return f"Заказ №{order_id} отправлен" handlers = {"paid": notify_paid, "shipped": notify_shipped} print(handlers["shipped"](1042))
Результат:
Заказ №1042 отправлен
Частые ошибки
key=get_price(). Скобки вызывают функцию сразу и без аргумента —TypeError: get_price() missing 1 required positional argument. Вkeyпередают функцию без скобок.maxпо значениям вместоkey.max(p["price"] for p in products)возвращает цену, а не товар. Нужен товар —max(products, key=...).mapбезlist().map/filterвозвращают ленивый объект, а не список; повторный обход не даст ничего.- Сложная логика в lambda. Если lambda не помещается в строку или нужна в нескольких местах — пишите
defс именем. - Сортировка по строке-числу.
key=lambda p: p["price"]при ценах-строках сортирует посимвольно:"990"после"1200". Приводите тип в ключе:int(p["price"]).
Итог
Функция — значение
- Имя без скобок — функция, со скобками — вызов.
- Функции кладут в переменные, списки, словари, передают и возвращают.
key
sorted/min/max(коллекция, key=функция)— сравнение по результату функции.min/maxсkeyвозвращают элемент; ключ-кортеж — сортировка по нескольким полям;-x— обратный порядок поля.
lambda, map, filter
lambda аргументы: выражение— короткая безымянная функция.map/filterленивые —list(...)для списка; чаще выбирают comprehension.
Вопросы на собеседовании
Что значит «функции — объекты первого класса»?
С функцией можно обращаться как с любым значением: присвоить переменной, положить в коллекцию, передать в другую функцию и вернуть из функции. На этом построены key=, колбэки, обработчики, декораторы.
Чем lambda отличается от обычной функции?
lambda — та же функция, но без имени и только из одного выражения, результат которого возвращается автоматически. В ней нельзя писать инструкции (if как оператор, циклы, присваивания). Для логики, которую нужно читать и тестировать, — def.
Как отсортировать товары по категории, а внутри — по убыванию цены?
Ключ-кортежем с минусом у числового поля: sorted(products, key=lambda p: (p["category_id"], -p["price"])). Для нечисловых полей используют две стабильные сортировки: сначала по второстепенному полю, потом по главному.