Распаковка в Python: звёздочка, обмен значений, деструктуризация
Этот урок переведён с английского оригинала.Read in EnglishLeer en españolСообщить об ошибке в переводе
Представьте, что вы заказали посылку, в которой три вещи: книга, наушники и чехол для телефона. Когда коробка приходит, вы открываете её и раскладываете всё по местам. Книга отправляется на полку, наушники на стол, а чехол на телефон.
Распаковка в Python работает так же. Вы берёте набор значений (кортеж, список или любой итерируемый объект) и одной аккуратной строкой присваиваете каждое значение своей переменной. Не нужно доставать элементы по одному через индексы.
В этом уроке вы изучите базовую распаковку, изящный приём обмена значений переменных, выражения со звёздочкой, которые собирают сразу несколько элементов, распаковку в циклах и деструктуризацию вложенных данных.
Как работает базовая распаковка?
Если у вас есть кортеж или список из нескольких значений, каждое из них можно присвоить отдельной переменной одной строкой. Число переменных слева должно совпадать с числом элементов справа.
10 20 30 red green blue
Без распаковки пришлось бы обращаться к каждому элементу по индексу. С распаковкой код становится короче и читается гораздо легче.
point = (10, 20, 30)
x = point[0]
y = point[1]
z = point[2]
print(x, y, z)point = (10, 20, 30)
x, y, z = point
print(x, y, z)Распаковывать можно и прямо в присваивании, не создавая сначала отдельный кортеж в переменной. Когда вы перечисляете значения через запятую, Python сам собирает из них кортеж.
Alice 25 Paris <class 'tuple'>
Как поменять значения переменных местами одной строкой
В большинстве языков программирования, чтобы поменять местами значения двух переменных, нужна временная переменная. Благодаря распаковке в Python она не нужна. Обмен значений умещается в одну изящную строку.
world hello
Это работает, потому что Python сначала вычисляет правую часть и упаковывает значения в кортеж (b, a), а затем распаковывает его в a, b. Всё происходит за один безопасный шаг.
a = 1
b = 2
temp = a
a = b
b = temp
print(a, b) # 2 1a = 1
b = 2
a, b = b, a
print(a, b) # 2 1Так же можно переставить значения трёх и более переменных. Python справится с этим за один шаг.
Before: a=1, b=2, c=3 After: a=2, b=3, c=1
Что такое выражения со звёздочкой (*rest)?
Иногда вы не знаете точно, сколько элементов в коллекции, или вам нужны лишь несколько конкретных. Выражение со звёздочкой (*variable) собирает все оставшиеся элементы в список.
1 [2, 3, 4, 5] [1, 2, 3, 4] 5
Звёздочку можно поставить и в середину. Это удобно, когда вам нужны первый и последний элементы, а всё, что между ними, можно пропустить.
First: 95 Middle: [80, 75, 90, 85, 70] Last: 88
10 20 [] H ['e', 'l', 'l'] o
Как использовать распаковку в циклах for
Особенно хорошо распаковка показывает себя в циклах for. Когда вы перебираете список кортежей (или списков), каждый элемент можно сразу распаковать в именованные переменные, а не обращаться к ним по индексу.
Alice is 16 years old Bob is 15 years old Charlie is 17 years old
Этот приём постоянно применяют вместе с enumerate() и dict.items(). Обе функции возвращают кортежи, и распаковка делает код намного чище.
0: apple 1: banana 2: cherry Alice -> 16 Bob -> 15 Charlie -> 17
Как распаковывать вложенные структуры данных
Распаковка в Python может уходить на несколько уровней вглубь. Если значение внутри коллекции само является кортежем или списком, его можно распаковать с помощью вложенных скобок в левой части.
Alice: 95, 87, 92
Это работает на любой глубине. Вложенную распаковку можно даже сочетать с выражениями со звёздочкой, чтобы получить максимум гибкости.
Alice: average = 91.3 Bob: average = 84.3 Charlie: average = 85.3
Частые ошибки при распаковке
Когда вы освоитесь, распаковка покажется интуитивной, но есть несколько ловушек, в которые часто попадают новички.
Alice 10 20 42 <class 'list'>
Упражнения для практики
Распакуйте кортеж point в три переменные: x, y и z. Затем выведите их в одну строку через пробел с помощью print(x, y, z).
В переменных first и second лежат не те значения. Поменяйте их местами с помощью распаковки (одной строкой, без временной переменной), а затем выведите обе переменные.
С помощью выражения со звёздочкой распакуйте список numbers в head (первый элемент) и tail (все остальные). Выведите обе переменные на отдельных строках.
Что выведет этот код? Подумайте, что соберёт звёздочка и каким типом это станет.
a, *b, c = [1, 2, 3, 4, 5, 6]
print(a)
print(b)
print(c)Запустите код, чтобы проверить свой ответ.
У вас есть список записей об учениках. Каждая запись представляет собой кортеж вида (name, (math_score, english_score)). С помощью вложенной распаковки в цикле for вычислите и выведите средний балл каждого ученика.
Выводите каждую строку в формате Name: average, где average округлено до одного знака после запятой с помощью :.1f.