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

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

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

Распаковка кортежей в Python: x, y = point

Один кортеж — несколько переменных за один шаг: x, y = point. Классический обмен значений, звёздочка для остатка и почему распаковывать множества опасно.

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

Кортеж из урока 11 — пачка значений. Доставать их по одному через point[0] и point[1] можно, но для пары и тройки есть путь короче: распаковка — одна строка раздаёт значения по переменным. Она встречается всюду: в циклах по словарям, в возврате из функций, в обмене значений.

Базовая распаковка

координаты в две переменные
point = (2, 3)

x, y = point
print(x)
print(y)
print(x + y)
Вывод
2
3
5

Слева — переменные через запятую, справа — кортеж. Значения разложились по порядку: первый элемент в x, второй в y. Скобки слева не нужны: x, y = point и (x, y) = point — одно и то же. Работает и прямой список значений: x, y = 4, 8 — справа собирается кортеж и тут же распаковывается.

Обмен значений одной строкой

swap без третьей переменной
a = 1
b = 2

a, b = b, a
print(a, b)
Вывод
2 1

Классика: a, b = b, a меняет значения местами без временной переменной. Справа сначала собирается кортеж (2, 1) со старыми значениями, и только потом он распаковывается в a и b — поэтому значения не затирают друг друга.

Число переменных должно совпадать

Переменных слева должно быть ровно столько, сколько элементов справа: лишняя или недостающая переменная — это ValueError.

не хватает значений
point = (2, 3)
x, y, z = point
print(x, y, z)
Вывод
Traceback (most recent call last):
  File "app.py", line 2, in <module>
    x, y, z = point
    ^^^^^^^
ValueError: not enough values to unpack (expected 3, got 2)
Программа падает на распаковке: переменных три, значений два. Обратная ошибка звучит симметрично: too many values to unpack.

Сообщение читается легко: ждали три значения, пришли два. При лишних значениях формулировка симметрична: too many values to unpack (expected 2) — значений больше, чем переменных.

Звёздочка: остаток в список

first и остальные
sizes = (36, 38, 40, 42, 44)

first, *rest = sizes
print(first)
print(rest)
print(type(rest))
Вывод
36
[38, 40, 42, 44]
<class 'list'>

Звёздочка перед именем собирает всё лишнее в список — не в кортеж: rest оказался list. Это удобно для схемы «первый и остальные»: первый размер отдельно, остальные пачкой.

звёздочка в середине
data = (1, 2, 3, 4, 5)

a, *mid, b = data
print(a, mid, b)
Вывод
1 [2, 3, 4] 5

Крайние значения — по именам, середина — списком. Звёздочка может стоять только одна: две звёздочки в одном присваивании — синтаксическая ошибка ещё до запуска.

Распаковка других последовательностей

список, строка, range
first, second = [10, 20]
a, b, c = 'кот'
x, y = range(2)

print(first + second)
print(a, b, c)
print(x, y)
Вывод
30
к о т
0 1

Механизм один для всех последовательностей: строка распадается на символы, range — на числа. Именно поэтому работал цикл по словарю из урока 8 курса про словари: for name, price in prices.items() распаковывал каждую пару-кортеж.

распаковка в заголовке цикла
pairs = ((1, 10), (2, 20))

for num, val in pairs:
    print(num, val * 2)
Вывод
1 20
2 40

Звёздочка при вызове функции

print(*point)
point = (2, 3)

print(*point)
print(point)
print(max(*point))
Вывод
2 3
(2, 3)
3

Звёздочка в вызове разворачивает кортеж в отдельные аргументы: print(*point) — то же, что print(2, 3). Без звёздочки print напечатал бы кортеж целиком, со скобками и запятой. А max(*point) — то же, что max(2, 3): функция получила два аргумента.

ЗаписьЧто делает
x, y = pointэлементы в переменные по порядку
a, b = b, aобмен значений через временный кортеж
first, *rest = tостаток собирается в список
a, *mid, b = tкрая по именам, середина списком
print(*t)распаковка при вызове функции

Что дальше

Распаковка — входная дверь в идиомы функций: в уроке 14 функция научится возвращать несколько значений разом — кортежем, который вы уже умеете разбирать. А в уроке 15 у кортежа появятся имена полей: namedtuple.

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

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

t = (5, 10)

x, y = t
x, y = y, x
print(x, y)
nums = (1, 2, 3, 4)

a, *b = nums
print(a)
print(len(b))
p = (1, 2, 3)

x, *mid, z = p
print(mid)
Проверь себя
0 / 8

1. Что произойдёт при x, y = (1, 2, 3)?

2. Что делает a, b = b, a?

3. Какого типа rest после first, *rest = (1, 2, 3)?

4. Почему x, y = {3, 1} — плохая идея?

5. Чему эквивалентен вызов print(*point) при point = (2, 3)?

6. Сколько звёздочек может быть в одном присваивании?

7. Что попадёт в a после a, b, c = 'кот'?

8. Что происходит в for name, price in prices.items():?

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

Дан кортеж dims = (30, 15) — ширина и высота. Распакуйте его в w и h, выведите периметр 2 * (w + h), затем поменяйте значения местами и выведите их одной строкой через print(w, h).

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

Что такое распаковка кортежа?

Раздача элементов последовательности переменным за один шаг: x, y = point кладёт первый элемент в x, второй — в y. Скобки слева не нужны, работает и с прямым перечислением: x, y = 4, 8.

Урок 11: tuple — неизменяемый кортеж

Сколько переменных нужно слева?

Ровно столько, сколько элементов справа: несовпадение даёт ValueError — too many values to unpack при лишних значениях, not enough values to unpack при нехватке. Остаток без строгого счёта собирает звёздочка.

Что делает звёздочка при распаковке?

Собирает остаток в список: first, *rest = (1, 2, 3, 4) даёт first = 1 и rest = [2, 3, 4]. В вызове функций звёздочка работает наоборот — разворачивает коллекцию в отдельные аргументы: print(*point).

Можно ли распаковать список или строку?

Да: распаковка работает с любой последовательностью — список, строка, range. Множества не стоит: их порядок не гарантирован, и в переменные попадёт непредсказуемый набор. Нужна определённость — сначала sorted.

Где ещё встречается распаковка?

В цикле по парам словаря: for name, price in prices.items(). В возврате из функций — функция возвращает кортеж, вызывающий код его распаковывает. И в присваивании через enumerate: for i, value in enumerate(items).

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

«Переменных слева должно быть ровно столько, сколько элементов справа: лишняя или недостающая переменная — это ValueError.»

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

TelegramVK

Что дальше

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

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

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