Распаковка, *args и **kwargs в сигнатурах и вызовах
Содержание курса
В предыдущем уроке мы работали с zip, enumerate и sorted — функциями, которые возвращают итерируемые объекты. Теперь разберём механизм, который стоит за тем, как Python вообще умеет «раскладывать» итерируемое по переменным — и как этим управлять через звёздочку.
Распаковка итерируемого в присваивании: базовый синтаксис и *rest
Когда Python видит несколько переменных слева от = и итерируемое справа, он идёт по элементам итерируемого и раскладывает их по переменным слева направо. Это называется распаковкой.
point = (10, 20, 30)
x, y, z = point
print(x, y, z) # 10 20 30
Работает с любым итерируемым: кортежем, списком, строкой, результатом zip — чем угодно, что можно обойти циклом.
Проблема возникает, когда количество элементов заранее неизвестно или может меняться. Тут появляется звёздочный синтаксис.
first, *rest = [1, 2, 3, 4, 5]
print(first) # 1
print(rest) # [2, 3, 4, 5]
*rest собирает всё, что не «досталось» конкретным переменным, и упаковывает это в список — не в кортеж, именно в список. Звёздочная переменная может стоять не только в конце:
first, *middle, last = [1, 2, 3, 4, 5]
print(first) # 1
print(middle) # [2, 3, 4]
print(last) # 5
Пython сам вычисляет, сколько элементов уйдёт в «звёздочную» переменную, ориентируясь на количество конкретных переменных вокруг.
Одно жёсткое ограничение: звёздочная переменная в одном присваивании может быть только одна. *a, *b = [1, 2, 3] — это SyntaxError. Python не умеет делить остаток между двумя «сборщиками».
Что происходит при несовпадении числа переменных
Если звёздочки нет, а количество переменных не совпадает с количеством элементов — получаем ValueError:
# Слишком много значений
a, b = [1, 2, 3] # ValueError: too many values to unpack
# Слишком мало значений
a, b, c = [1, 2] # ValueError: not enough values to unpack
Звёздочка страхует от этой ошибки, но только от одной стороны: если конкретных переменных больше, чем элементов, ValueError всё равно возникнет.
first, second, *rest = [1] # ValueError: not enough values to unpack
Здесь Python пытается отдать по одному элементу first и second, но элемент только один — rest тут уже ничего не поможет.
Этот механизм — основа для понимания того, как * работает при вызовах функций и в их сигнатурах. Но об этом в следующих секциях.
