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

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

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

Распаковка списка в 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]: две строки и два места, где легко перепутать номер. Распаковка работает с любым числом переменных — три, четыре, сколько угодно, — но число обязано совпасть с числом элементов:

несовпадение — ValueError
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 забирает остаток

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

*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))
Проверь себя
0 / 7

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?

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

Дан список results = [89, 45, 520, 210]. Распакуйте его так, чтобы минимальная цена и максимальная цена попали в отдельные переменные после сортировки, а середина — в список middle. Напечатайте min, max и длину середины.

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

Что такое распаковка списка в 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-канал или свой блог — так о проекте узнают новые читатели.

TelegramVK

Что дальше

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

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

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