Функция возвращает несколько значений: return с кортежем
Функция возвращает пару значений одной строкой: запятая в return собирает кортеж, распаковка раскладывает его по переменным. min и max за один проход, звёздочка для остатка.
Редакция Питоники
До сих пор функции возвращали одно значение: сумму, длину, отформатированную строку. Но половина жизненных задач просит два ответа разом: минимум и максимум списка, координаты точки, имя и возраст. Первое желание — написать две функции или спрятать вторую величину в глобальную переменную. Python предлагает путь короче: return с запятой. Функция собирает оба ответа в кортеж — структуру из урока 11 — и отдаёт одной посылкой, а распаковка из урока 13 раскладывает её по переменным. На этой паре держится половина чужого кода, который вам предстоит читать.
return с запятой: на самом деле это кортеж
Начнём с задачи, где двух ответов не избежать: найти в списке и минимум, и максимум. Функция min_max делает это за один вызов и возвращает обе величины:
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:
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, даже когда результат целый. Три переменные за один вызов, у каждой осмысленное имя — такой вызов читается как предложение. Три значения — удобный потолок: дальше читателю уже трудно держать в голове порядок возвратов.
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, b | a, 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])
1. Что на самом деле возвращает return a, b?
2. Как принять два возвращённых значения в две переменные?
3. Функция возвращает два значения, а слева стоят три имени. Что случится?
4. Что окажется в rest после first, *rest = f(), если f вернула кортеж из четырёх значений?
5. Почему для температуры и влажности советуют словарь или namedtuple, а не кортеж?
6. Что вернёт os.path.split('docs/report.txt')?
7. Сколько значений удобно возвращать кортежем без имён?
Напишите функцию bounds(nums), которая возвращает наименьшее и наибольшее число списка, распакуйте результат в low и high и напечатайте строку «low = 3, high = 10» для списка [10, 3, 7].
Как вернуть из функции 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-канал или свой блог — так о проекте узнают новые читатели.
Что дальше
Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.
Что читать дальше
Множества · Урок 13
Распаковка кортежей в Python: x, y = point
Один кортеж — несколько переменных за один шаг: x, y = point. Классический обмен значений, звёздочка для остатка и почему распаковывать множества опасно.
Множества · Урок 11
Tuple в Python: неизменяемый кортеж и доступ по индексу
Кортеж хранит фиксированный набор значений и защищает его от изменений: создали — и состав застыл. Создание, доступ по индексу, IndexError и то, почему запятая главнее скобок.
Множества · Урок 15
namedtuple в Python: кортеж с именами полей
namedtuple даёт кортежу имена полей: p.x вместо p[0], читаемый repr и всё кортежное на месте — индексы, распаковка, сравнение. Шесть строк кода, и записи перестают быть наборами индексов.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
Функции · Урок 3
Return в Python: функция возвращает результат
print показывает значение человеку, return отдаёт программе. Учимся возвращать результат, класть его в переменную и использовать в выражениях — и не путать return с print.
python returnreturn python
Функции · Урок 11
**kwargs в Python: именованные на подхвате
Позиционные аргументы умеет собирать звёздочка — а какие именованные прислал вызов, заранее не знал никто. Разбираем двойную звёздочку и словарь настроек.
распаковка словаря pythonконфиг функция python
Множества · Урок 12
Кортеж против списка в Python: что и когда использовать
У обоих есть индексы, len и in, но список можно менять, а кортеж — нет. Четыре отличия: изменяемость, ключ словаря, память и правило выбора за три секунды.
python кортеж против спискакортеж или список python