Распаковка списка в Python: звёздочка и остаток
name, price = пара без индексов, swap одной строкой, *rest забирает остаток, print(*items) печатает без скобок. Одна звёздочка — четыре приёма, которые сжимают списочный код вдвое.
Редакция Питоники
Половина курса уже прошла через распаковку, не называя её: цикл for name, price in zip(...) из урока про пары, разбор записи record.split(':') из урока про join и split. Пора присвоить приёму имя и добрать недостающее: несовпадение числа переменных, звёздочка для остатка, распаковка при вызовах и в литералах. После этого урока списочный код сжимается вдвое — а в проекте раздела распаковка встречается в каждой строке разбора.
Распаковка: a, b = список
Слева от равно стоят переменные через запятую, справа — список. Python раздаёт элементы по порядку, без единого индекса:
pair = ['молоко', 89]
name, price = pair
print(name, '-', price, 'руб')
print(len(pair))
молоко - 89 руб 2
То же самое с индексами выглядело бы как name = pair[0] и price = pair[1]: две строки и два места, где легко перепутать номер. Распаковка работает с любым числом переменных — три, четыре, сколько угодно, — но число обязано совпасть с числом элементов:
pair = ['молоко', 89]
try:
name, price, qty = pair
except ValueError as e:
print('Ошибка:', e)
Ошибка: not enough values to unpack (expected 3, got 2)
Сообщение честно считает с обеих сторон: ожидали три переменные, а элементов два — not enough values to unpack. Обратный случай, когда элементов больше, чем переменных, даёт зеркальное too many values to unpack. Если точное число заранее неизвестно — в дело идёт звёздочка.
Звёздочка: *rest забирает остаток
Переменная со звёздочкой собирает всё, что не разобрали соседи, и всегда получает список. Первый элемент отдельно, остаток — целиком:
ratings = [10, 9, 8, 7, 6]
first, *rest = ratings
print(first)
print(rest)
*head, last = ratings
print(head)
print(last)
10 [9, 8, 7, 6] [10, 9, 8, 7] 6
first и last разобрали края, звёздочка забрала всё посередине — неважно, сколько там элементов. Звёздочку можно ставить и в середину: a, *mid, b = ratings отдаст края по переменным, середину списком. Звёздочка в присваивании собирает остаток в список: он всегда список, даже когда забирать нечего. Убедимся на крайнем случае — список из одного элемента:
only = [42]
first, *rest = only
print(first)
print(rest)
print(type(rest).__name__)
42 [] list
rest остался честным пустым списком — цикл по нему просто не выполнится, и отдельных проверок не требуется. Второе правило жёстче: звёздочек в одном присваивании ровно одна — две переменные со звёздочкой Python разбираться не возьмёт и ответит SyntaxError.
Swap одной строкой
Классическая задача — поменять две переменные местами — решается распаковкой без временной буферной переменной: справа заранее собирается кортеж из старых значений, слева они раздаются заново:
first = 'молоко'
second = 'хлеб'
first, second = second, first
print(first, second)
хлеб молоко
Строка first, second = second, first — распаковка в чистом виде: правая часть собирает пару из текущих значений, левая раздаёт. В чужом коде swap встречается постоянно, и теперь он читается без усилий. Пригодится и для списков: tops[0], tops[1] = tops[1], tops[0] меняет местами два лидера рейтинга.
Звёздочка при вызове: print(*список)
Та же звёздочка работает при вызове функций: список распаковывается в отдельные аргументы. print получает элементы по одному, и печать выходит без скобок и кавычек:
items = ['молоко', 'хлеб', 'сыр']
print(items)
print(*items)
print(*items, sep=', ')
print(*items, sep='')
['молоко', 'хлеб', 'сыр'] молоко хлеб сыр молоко, хлеб, сыр молокохлебсыр
Первая печать — отладочная: со скобками, кавычками и запятыми видно структуру. Остальные — пользовательские: print(*items) раздал элементы по одному аргументу, а sep управляет разделителем. Тот же приём передаёт список в любую функцию с несколькими аргументами — механика *args подробно разбирается в курсе про функции.
Звёздочка в литералах: склейка списков
Третье место звёздочки — внутри нового списка: [*a, *b] вкладывает элементы обоих списков в один новый. Плюс склеивает два списка, звёздочка — любое число частей без вложенных скобок:
fresh = ['молоко', 'хлеб']
frozen = ['мороженое']
dry = ['макароны', 'крупа']
cart = [*fresh, *frozen, *dry]
print(cart)
print(len(cart))
plus = fresh + frozen
print(plus, plus is fresh)
['молоко', 'хлеб', 'мороженое', 'макароны', 'крупа'] 5 ['молоко', 'хлеб', 'мороженое'] False
Три списка слились в один новый cart, и ни один источник не изменился — звёздочка не мутирует, она раскладывает элементы внутри литерала. Плюс делает то же для двух частей, но при трёх и больше скобки растут, а [*a, *b, *c] читается одинаково для любого числа частей. Новые списки — новая структура: правки cart не тронут fresh, это копирование из урока про ссылки в квадрате.
Четыре места звёздочки
| Место | Запись | Что происходит |
|---|---|---|
| Присваивание без звёздочки | a, b = pair | Число переменных равно числу элементов, иначе ValueError |
| Присваивание со звёздочкой | first, *rest = xs | Остаток собирается в список, звёздочка одна |
| Вызов функции | print(*items) | Список распаковывается в отдельные аргументы |
| Литерал списка | [*a, *b, *c] | Элементы нескольких списков сливаются в новый |
Распаковка и звёздочка — последний инструмент перед финалом: в проекте инвентаря разбор записей идёт через name, price, qty = record.split(':'), а печать отчёта через zip и звёздочку. Загляните и в задачи раздела: половина решений там становится короче с распаковкой в заголовке цикла.
Сначала предскажи ответ в голове — это главный навык программиста.
nums = [1, 2, 3, 4]
a, *mid, b = nums
print(a, b, len(mid))
items = ['а', 'б', 'в']
print(*items, sep='-')
a = [1, 2]
b = [3]
c = [*a, *b]
c.append(4)
print(c, len(a))
1. Что произойдёт при a, b = [1, 2, 3]?
2. После first, *rest = [10, 9, 8] что лежит в rest?
3. Что получит rest при first, *rest = [42]?
4. Сколько переменных со звёздочкой допускается в одном присваивании?
5. Чем print(*items) отличается от print(items)?
6. Что делает [*a, *b, *c]?
7. Как работает обмен first, second = second, first?
Дан список results = [89, 45, 520, 210]. Распакуйте его так, чтобы минимальная цена и максимальная цена попали в отдельные переменные после сортировки, а середина — в список middle. Напечатайте min, max и длину середины.
Что такое распаковка списка в Python?
Присваивание вида a, b = ['молоко', 89]: Python раздаёт элементы списка переменным без индексов. Число переменных обязано совпасть с числом элементов, иначе ValueError. В цикле распаковка встречается как заголовок for name, price in zip(...).
Урок 19: распаковка и звёздочкаЧто делает звёздочка при распаковке?
Собирает остаток в список: first, *rest = [10, 9, 8] даёт first = 10 и rest = [9, 8]. Остаток всегда список, даже пустой; звёздочек в одном присваивании может быть только одна, иначе SyntaxError.
Как поменять значения двух переменных местами?
Одной строкой распаковки: first, second = second, first. Правая часть собирает кортеж из старых значений, левая раздаёт их заново — буферная переменная не нужна.
Как напечатать список без скобок и кавычек?
Распаковкой при вызове: print(*items) подаёт элементы отдельными аргументами, и print печатает их через пробел. Разделитель меняет sep: print(*items, sep=', ') даёт элементы через запятую без скобок.
Как склеить несколько списков через звёздочку?
В литерале нового списка: [*a, *b, *c] раскладывает элементы всех трёх списков в один новый. Это то же, что a + b + c, но читается одинаково для любого числа частей и не меняет исходные списки.
Урок 14: zip(*pairs)Понравился урок? Сошлитесь на него
«Звёздочка в присваивании собирает остаток в список: он всегда список, даже когда забирать нечего.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что дальше
Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.
Что читать дальше
Списки · Урок 14
Zip в Python: параллельные списки в пары
Товары лежат в одном списке, цены — в другом, а идти по ним нужно синхронно. Функция zip собирает пары одной строкой: цикл без индексов, обрезание по кратнейшему и unzip через звёздочку.
Списки · Урок 16
Join и split в Python: строка и список
Данные приходят строкой «молоко,хлеб,сыр», а работать с ними удобнее списком. split режет строку на части, join склеивает обратно — мост между двумя мирами.
Списки · Урок 20
Проект на Python: инвентарь магазина на списках
Финальный проект: маленький магазин — товары, цены и остатки в трёх параллельных списках. zip собирает записи, sum и max считают агрегаты, сортировка даёт топ, comprehension находит дефицит — и всё складывается в отчёт.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
Множества · Урок 13
Распаковка кортежей в Python: x, y = point
Один кортеж — несколько переменных за один шаг: x, y = point. Классический обмен значений, звёздочка для остатка и почему распаковывать множества опасно.
python распаковка кортежейраспаковка кортежа python
Циклы · Урок 10
zip в Python: несколько последовательностей параллельно
Два списка идут параллельно: имена и баллы, товары и цены. zip склеивает их в пары, цикл берёт по одной — без индексов и range(len(...)).
zip два списка pythonраспаковка кортежа python
Списки · Урок 3
Python insert и extend: вставка по индексу и добавление пачкой
insert ставит элемент по индексу и сдвигает остальных вправо, extend раскладывает пачку на отдельные элементы. Оба меняют список на месте и возвращают None.
python вставить элемент в списокpython добавить список в список