Перейти к содержимому
Теория · Функции как значения · урок 3 из 10

Функции как значения

Представьте, что вы отдаёте помощнику стопку карточек со словами и просите их разложить. Сортировать он умеет, но не знает, по какому правилу. Тогда вы даёте ему записку: «сравнивай слова по длине». В Python такая записка — это функция, которую передают другой функции.

Функция sorted упорядочивает строки по алфавиту. Чтобы отсортировать слова по длине, ей нужно сообщить, что сравнивать. Для этого sorted передают другую функцию — в именованном аргументе key:

Python
words = ["banana", "fig", "apple", "kiwi"]
print(sorted(words))  # ['apple', 'banana', 'fig', 'kiwi']
print(sorted(words, key=len))  # ['fig', 'kiwi', 'apple', 'banana']

Давайте разберём пример по строкам:

  1. sorted(words) сравнивает сами строки, буква за буквой, и раскладывает их по алфавиту.
  2. sorted(words, key=len) получает записку len и вызывает её для каждого слова: 6, 3, 5, 4.
  3. Сортировка идёт по этим числам, а в результат попадают сами слова, от fig до banana.

Как вы уже знаете, так же key работает у min и max.

Функция — это значение

Имя функции без скобок — это сама функция, а со скобками — её вызов:

  • len — функция, записка с правилом;
  • len("fig") — результат вызова, число 3.

Функцию, как число или строку, можно присвоить переменной или передать аргументом. С аргументом key функция sorted вызывает len по одному разу для каждого слова и сравнивает результаты, а не сами слова.

Передать можно и свою функцию. Функцию, которая принимает другую функцию или возвращает её, называют функцией высшего порядка: sorted с key — одна из них.

Python
def last_letter(word):
    return word[-1]


words = ["banana", "fig", "apple", "kiwi"]
check = last_letter
print(check("fig"))  # g
print(sorted(words, key=last_letter))  # ['banana', 'apple', 'fig', 'kiwi']

Разберём по шагам:

  1. check = last_letter не вызывает функцию, а даёт ей второе имя. Переменная check указывает на ту же функцию.
  2. check("fig") вызывается так же, как last_letter("fig"), и возвращает g.
  3. sorted(words, key=last_letter) сортирует слова по последней букве: a, e, g, i.

Здесь аналогия с запиской перестаёт работать. Записку читают один раз, а функцию sorted вызывает заново для каждого элемента. Каждый раз она получает один элемент и возвращает его ключ.

lambda

Ради одного key заводить отдельный def долго. Лямбда-функция — функция без имени, записанная в одно выражение: lambda word: word[-1] делает то же, что last_letter. Запись состоит из трёх частей:

  1. слово lambda;
  2. параметры перед двоеточием;
  3. выражение после двоеточия — его значение функция возвращает, без слова return.
Python
scores = [("max", 3), ("lee", 5), ("kim", 3)]
by_score = sorted(scores, key=lambda s: s[1])
print(by_score)  # [('max', 3), ('kim', 3), ('lee', 5)]

Ключ здесь — второй элемент кортежа, число очков. Ключи max и kim равны, и sorted сохранил исходный порядок: max стоял раньше, хотя по алфавиту kim идёт первым.

Сортировка в Python устойчивая: элементы с равными ключами сохраняют порядок, в котором стояли. Так же сортирует метод sort с аргументом key. Об устойчивости сортировки часто спрашивают на собеседовании, обычно на примере вроде этого.

map и filter

Встроенные map и filter тоже принимают функцию первым аргументом. Как генераторное выражение, они выдают значения по одному, поэтому результат оборачивают в list.

map

map вызывает функцию для каждого элемента и выдаёт её результаты. list(map(len, words)) даёт [6, 3, 5, 4], длину каждого слова.

filter

filter оставляет элементы, для которых функция вернула истинное значение. list(filter(lambda w: len(w) > 4, words)) даёт ['banana', 'apple'].

Чаще вместо обеих функций пишут включение, потому что оно читается проще. Те же результаты дают [len(w) for w in words] и [w for w in words if len(w) > 4].

Частая ошибка

В key передали вызов функции вместо самой функции:

Python
words = ["banana", "fig", "apple", "kiwi"]
print(sorted(words, key=len()))  # ✗
TEXT
TypeError: len() takes exactly one argument (0 given)

Скобки вызывают len сразу, ещё до сортировки, и без аргумента. Даже с аргументом в key попало бы число, а не функция. Пишите имя без скобок: key=len.

Главное

  • Имя функции без скобок — сама функция: её можно присвоить переменной или передать аргументом.
  • sorted, min и max вызывают функцию из key для каждого элемента и сравнивают её результаты.
  • lambda x: выражение — короткая функция без имени, которая возвращает значение выражения.
  • Сортировка устойчивая: элементы с равными ключами сохраняют исходный порядок.

Подпишись, чтобы пройти курс

Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.

Войти другим способом