Распаковка кортежей в Python: подробное руководство
Распаковка кортежей в Python: базовый синтаксис, звёздные выражения, вложенные кортежи, распаковка в циклах и типичные ошибки.
Распаковка кортежей (также называется распаковкой итерируемых объектов) позволяет присвоить элементы кортежа — или любого итерируемого объекта — отдельным переменным в одном выражении. Эта страница охватывает всё: от базового синтаксиса до продвинутых паттернов, таких как звёздные выражения, вложенная распаковка и распаковка в циклах.
Что такое распаковка кортежей?
При распаковке кортежа Python сопоставляет каждый элемент с соответствующей переменной в левой части =. Количество переменных должно точно совпадать с количеством элементов (если только вы не используете звёздное выражение, о котором речь пойдёт ниже).
Скобки вокруг кортежа необязательны — 1, 2, 3 тоже является кортежем. Обе следующие строки эквивалентны:
a, b, c = (1, 2, 3)
a, b, c = 1, 2, 3 # same resultЗачем использовать распаковку кортежей?
Лаконичное присваивание переменных
Без распаковки вам потребуется отдельная строка для каждого элемента:
Обмен значений переменных
Распаковка позволяет поменять два значения местами в одну строку. Python полностью вычисляет правую часть перед присваиванием, поэтому временная переменная не нужна:
Чтение возвращаемых значений функций
Функции, возвращающие несколько значений, на самом деле возвращают кортеж. Распаковка позволяет сразу дать каждому значению понятное имя:
def min_max(numbers):
return min(numbers), max(numbers)
lo, hi = min_max([3, 1, 4, 1, 5, 9, 2, 6])
print(lo) # 1
print(hi) # 9Без распаковки пришлось бы писать result[0] и result[1], что менее читаемо.
Расширенная распаковка с оператором звёздочки
Если вы не знаете (или вас не интересует) количество средних элементов, добавьте * перед одной переменной, чтобы она захватила всё, что не соответствует именованным слотам. Помеченная переменная всегда получает список, даже если она захватывает ноль элементов.
Захват хвоста
first, *rest = (1, 2, 3, 4, 5)
print(first) # 1
print(rest) # [2, 3, 4, 5]Захват головы
*start, last = (1, 2, 3, 4, 5)
print(start) # [1, 2, 3, 4]
print(last) # 5Захват средней части
first, *middle, last = (10, 20, 30, 40, 50)
print(first) # 10
print(middle) # [20, 30, 40]
print(last) # 50В одном выражении распаковки допускается только одна помеченная переменная. Использование двух и более вызывает SyntaxError.
Игнорирование элементов с помощью _
В Python принято использовать _ в качестве имени «мусорной» переменной. Это допустимый идентификатор — Python просто присваивает ему значение, — но по соглашению он сигнализирует: «Это значение мне не нужно».
x, _, z = (10, 99, 30)
print(x) # 10
print(z) # 30
# _ holds 99 but we do not use itКомбинируйте _ со звёздным выражением, чтобы отбросить несколько элементов:
first, *_ = (10, 20, 30, 40)
print(first) # 10
# *_ swallows 20, 30, 40Вложенная распаковка кортежей
Если кортеж содержит другой кортеж, вы можете распаковать оба уровня в одном выражении, отразив вложенность с помощью скобок:
Это работает на любой глубине, но глубокая вложенность ухудшает читаемость — лучше выполнять распаковку поэтапно.
Распаковка в циклах for
Вы можете распаковывать каждый элемент итерируемого объекта непосредственно в операторе for. Это особенно удобно при работе со списками кортежей:
pairs = [(1, 'one'), (2, 'two'), (3, 'three')]
for num, word in pairs:
print(num, word)
# 1 one
# 2 two
# 3 threeРаспаковка с enumerate()
enumerate() возвращает пары (индекс, значение), которые можно сразу распаковать:
fruits = ('apple', 'banana', 'cherry')
for i, fruit in enumerate(fruits):
print(i, fruit)
# 0 apple
# 1 banana
# 2 cherryЭто избавляет от ручного отслеживания индексов и является идиоматическим паттерном Python для итерации по последовательности, когда нужны и позиция, и значение.
Распаковка с zip()
zip() объединяет элементы двух итерируемых объектов в пары, и каждую пару можно распаковывать в цикле:
names = ('Alice', 'Bob', 'Carol')
scores = (92, 87, 95)
for name, score in zip(names, scores):
print(name, score)
# Alice 92
# Bob 87
# Carol 95Распространённые ошибки
Слишком много или слишком мало значений
Python вызывает ValueError, если количество переменных не совпадает с количеством элементов (и звёздное выражение отсутствует):
a, b = (1, 2, 3)
# ValueError: too many values to unpack (expected 2)a, b, c = (1, 2)
# ValueError: not enough values to unpack (expected 3, got 2)Устраните несоответствие или используйте звёздное выражение, чтобы поглотить лишние элементы.
Две переменные со звёздочкой
first, *middle, *last = (1, 2, 3, 4)
# SyntaxError: multiple starred expressions in assignmentВ одном выражении распаковки допускается только одна переменная с *.
Краткий справочник
| Паттерн | Пример | Что делает |
|---|---|---|
| Базовый | a, b, c = t | Присваивает каждый элемент именованной переменной |
| Звёздный хвост | first, *rest = t | Первый элемент именован; остаток захватывается как список |
| Звёздная голова | *start, last = t | Последний элемент именован; остаток захватывается как список |
| Звёздная середина | first, *mid, last = t | Первый и последний именованы; середина захватывается как список |
| Игнорировать один | x, _, z = t | Средний элемент отбрасывается по соглашению |
| Игнорировать многие | first, *_ = t | Сохраняется только первый элемент |
| Вложенный | a, (b, c), d = t | Внутренний кортеж распаковывается в том же выражении |
| Цикл | for x, y in pairs: | Каждая пара распаковывается на каждой итерации |
Связанные главы
- Python Tuples — создание, индексирование и нарезка кортежей
- Access Tuples — чтение отдельных элементов по индексу
- Loop Tuples — итерация по элементам кортежа
- Join Tuples — объединение нескольких кортежей
- Tuple Methods —
count()иindex() - Update Tuples — работа с неизменяемостью