Перейти к содержанию

412 уроков, 25 библиотек и челлендж «Что выведет код?» — бесплатно, код прямо в браузере

Начать обучение
Урок 14 из 20 Начальный 15 мин 100 XP

Функция возвращает несколько значений: return с кортежем

Функция возвращает пару значений одной строкой: запятая в return собирает кортеж, распаковка раскладывает его по переменным. min и max за один проход, звёздочка для остатка.

Редакция Питоники

До сих пор функции возвращали одно значение: сумму, длину, отформатированную строку. Но половина жизненных задач просит два ответа разом: минимум и максимум списка, координаты точки, имя и возраст. Первое желание — написать две функции или спрятать вторую величину в глобальную переменную. Python предлагает путь короче: return с запятой. Функция собирает оба ответа в кортеж — структуру из урока 11 — и отдаёт одной посылкой, а распаковка из урока 13 раскладывает её по переменным. На этой паре держится половина чужого кода, который вам предстоит читать.

return с запятой: на самом деле это кортеж

Начнём с задачи, где двух ответов не избежать: найти в списке и минимум, и максимум. Функция min_max делает это за один вызов и возвращает обе величины:

два ответа одним return
def min_max(nums):
    return min(nums), max(nums)

result = min_max([3, 1, 4, 1, 5])
print(result)
print(type(result))
Вывод
(1, 5)
<class 'tuple'>

Два значения приехали в одной посылке, и в выводе type это видно: tuple. Никакого особого синтаксиса вернуть несколько значений в Python нет: запятая в return собирает перечисленное в кортеж. Тот же самый результат получился бы и со скобками — return (min(nums), max(nums)) — потому что скобки у кортежей декоративные, работает запятая.

Распаковка: каждый ответ в свою переменную

Печатать кортеж целиком обычно не нужно: минимум ложится в одну переменную, максимум — в другую. Здесь работает распаковка: слева от знака равенства столько имён через запятую, сколько значений в кортеже.

распаковка результата вызова
def min_max(nums):
    return min(nums), max(nums)

low, high = min_max([3, 1, 4, 1, 5])
print('минимум:', low)
print('максимум:', high)
print('размах:', high - low)
Вывод
минимум: 1
максимум: 5
размах: 4

Один вызов — две готовые переменные, и синтаксис симметричен: запятая упаковала, запятая распаковала. Именно так идиому потребляют в реальном коде: писали через запятую — читаем через запятую. Имена low и high документируют себя сами, и это вторая причина популярности приёма.

Число имён обязано совпасть с числом значений

Распаковка строгая: имён слева должно быть ровно столько, сколько значений справа. Ошибка называет обе цифры — ожидаемую и приехавшую:

три имени на два значения
def min_max(nums):
    return min(nums), max(nums)

try:
    a, b, c = min_max([3, 1, 4])
except ValueError as e:
    print('ValueError:', e)
Вывод
ValueError: not enough values to unpack (expected 3, got 2)

Ожидалось три имени, приехали два — ValueError говорит это прямо. Лечится выравниванием числа имён по числу значений. А когда число значений заранее неизвестно или код должен переживать рост функции, помогает звёздочка.

Звёздочка собирает остаток

Если первое имя нужно само по себе, а остальное — пачкой, звёздочка перед именем забирает остаток. Приём тот же, что при распаковке списков в уроке 13, и работает на возвратах функций без изменений:

первое значение и остаток
def stats(nums):
    return len(nums), min(nums), max(nums), sum(nums)

count, *rest = stats([4, 8, 15, 16, 23])
print('первое значение:', count)
print('остаток:', rest)
print('тип остатка:', type(rest).__name__)
Вывод
первое значение: 5
остаток: [4, 23, 66]
тип остатка: list

Звёздочное имя всегда даёт список, даже если посылка была кортежем: Python распаковал четыре значения и свернул последние три в новый список. Приём не про лень, а про устойчивость: функция может вырасти с двух значений до пяти, и вызов со звёздочкой переживёт это без единой правки.

Статистика списка одним вызовом

Соберём рабочую версию: функция stats возвращает три величины — минимум, максимум и среднее. Среднее — это сумма, делённая на количество, и считается в том же return:

stats: три ответа за один вызов
def stats(nums):
    return min(nums), max(nums), sum(nums) / len(nums)

lo, hi, avg = stats([2, 4, 6, 8])
print('минимум:', lo)
print('максимум:', hi)
print('среднее:', avg)
Вывод
минимум: 2
максимум: 8
среднее: 5.0

Среднее напечаталось как 5.0 с хвостом: деление в Python всегда даёт float, даже когда результат целый. Три переменные за один вызов, у каждой осмысленное имя — такой вызов читается как предложение. Три значения — удобный потолок: дальше читателю уже трудно держать в голове порядок возвратов.

stats от пустого списка
def stats(nums):
    return min(nums), max(nums), sum(nums) / len(nums)

try:
    stats([])
except ValueError as e:
    print('ValueError:', e)
Вывод
ValueError: min() iterable argument is empty
СитуацияЧто возвращатьКак принимать
Одна величинаОбычное значениеx = f(...)
Две-три связанныеКортеж: return a, ba, b = f(...)
Много или растётКортеж со звёздочкойfirst, *rest = f(...)
Имена важнее порядкаСловарьd = f(...); d['имя']

Идиома настолько стандартная, что сама стандартная библиотека так работает: os.path.split делит путь на папку и имя файла и возвращает пару.

так делает и стандартная библиотека
import os

head, tail = os.path.split('docs/report.txt')
print('папка:', head)
print('файл:', tail)
Вывод
папка: docs
файл: report.txt

Пара (docs, report.txt) распаковалась в две переменные, и ни один символ пути не потерялся. Заметьте: функция отдала кортеж, а не два аргумента — приём один и тот же и в библиотеке, и в вашем коде.

Что дальше

Запятая в return — самая короткая дорога от задачи «вернуть пару» к рабочему коду. Следующий шаг — дать значениям имена прямо в структуре: namedtuple делает кортеж с полями, и код читается как visitor.name вместо visitor[0]. А когда встанет задача почистить список от повторов, пригодится приём из урока про дубликаты — одна строка с множеством.

Функция возвращает несколько значений одним кортежем, распаковка принимает их поимённо — и посередине нет ни словарей, ни глобальных переменных. Две запятые: одна в return, другая слева от равенства.

Что выведет код?

Сначала предскажи ответ в голове — это главный навык программиста.

def divmod_like(n, d):
    return n // d, n % d

q, r = divmod_like(17, 5)
print(q, r)
print(q + r)
def pair():
    return 1, 2

a, *rest = pair()
b = rest
print(a, rest, len(rest))
def f():
    return 10, 20

result = f()
print(result[0] + result[1])
Проверь себя
0 / 7

1. Что на самом деле возвращает return a, b?

2. Как принять два возвращённых значения в две переменные?

3. Функция возвращает два значения, а слева стоят три имени. Что случится?

4. Что окажется в rest после first, *rest = f(), если f вернула кортеж из четырёх значений?

5. Почему для температуры и влажности советуют словарь или namedtuple, а не кортеж?

6. Что вернёт os.path.split('docs/report.txt')?

7. Сколько значений удобно возвращать кортежем без имён?

Карточки терминов
Запомнено: 0 / 7
Практика

Напишите функцию bounds(nums), которая возвращает наименьшее и наибольшее число списка, распакуйте результат в low и high и напечатайте строку «low = 3, high = 10» для списка [10, 3, 7].

practice.py
Вопросы и ответы по уроку

Как вернуть из функции Python несколько значений?

Перечислить их в return через запятую: return min(nums), max(nums). Python соберёт перечисленное в кортеж, и функция вернёт один объект с двумя значениями внутри. Принимающая сторона распаковывает кортеж: low, high = min_max(nums).

Урок 13: распаковка кортежей

Можно ли вернуть три и больше значений?

Можно: return a, b, c соберёт кортеж из трёх. Но у кортежа нет имён, и читателю приходится помнить порядок, поэтому рабочий потолок — две-три связанные величины. Для большего числа значений возвращайте словарь или namedtuple — там поля доступны по имени.

Урок 15: namedtuple — кортеж с именами полей

Почему return a, b возвращает кортеж, а не два значения?

Потому что специального синтаксиса возврата нескольких значений в Python нет: запятая — это оператор сборки кортежа. Функция всегда возвращает один объект, и здесь это кортеж (a, b); «вернуть несколько значений» — удобное название для этой идиомы.

Что делать, если число возвращаемых значений может измениться?

Принимать со звёздочкой: first, *rest = f(x). Первое значение ляжет в first, остальные — списком в rest, и рост функции с двух значений до пяти не сломает вызов.

Что лучше вернуть — кортеж или словарь?

Кортеж — когда значений два-три, они связаны по смыслу, а порядок очевиден: минимум и максимум, папка и файл. Словарь — когда у значений устойчивые имена и перепутать их опасно: температура и влажность. Промежуточный вариант — namedtuple: доступ по имени при кортежной природе.

Урок 15: namedtuple

Понравился урок? Сошлитесь на него

«Никакого особого синтаксиса вернуть несколько значений в Python нет: запятая в return собирает перечисленное в кортеж.»

Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.

TelegramVK

Что дальше

Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.

Похожие уроки по темам

Подобраны автоматически по пересечению тем и ключевых слов.