Разберем префиксные операторы *
и **
, которые ставятся перед переменными для распаковки или упаковки коллекций.
Распаковка в переменные
Распаковка кортежей
Кортеж можно распаковать в отдельные элементы:
a, b = (1, 2) print(a) print(b) #1 #2
Но если в кортеже будет больше значений, чем переменных, то будет ошибка:
a, b = (1, 2, 3, 4) print(a) print(b) #ValueError: too many values to unpack (expected 2)
Можно воспользоваться оператором распаковки *
:
a, *b = (1, 2, 3, 4) print(a) print(b) #1 #[2, 3, 4]
В результате первый элемент кортежа будет присвоен первой переменной a
, а все остальные элементы (уже в виде списка) — переменной b
.
Также можно сделать и наоборот:
*a, b = (1, 2, 3, 4) print(a) print(b) #[1, 2, 3] #4
Переменной b
будет присвоен последний элемент кортежа, а все остальные будут присвоены переменной a
в виде списка.
Или так:
a, *b, c = (1, 2, 3, 4) print(a) print(b) print(c) #1 #[2, 3] #4
Крайние элементы кортежа присваиваются переменным a
и c
, а все остальное попадает в переменную b
.
Распаковка списков
a, *b = [1, 'два', 3, False] print(a) print(b) #1 #['два', 3, False]
Распаковка строк
a, *b, c = 'fullstacker.ru' print(a) print(b) print(c) #f #['u', 'l', 'l', 's', 't', 'a', 'c', 'k', 'e', 'r', '.', 'r'] #u
Распаковка множеств
s = {1, 2, 4} a, *b = s print(a) print(b) #1 #[2, 4]
Распаковка словарей
d1 = {'key1': 'val1', 'key2': 'val2', 'key3': 'val3'} a, *b = d1 print(a) print(b) #key1 #['key2', 'key3']
Получим ключи словаря.
Для получения значений, следует использовать метод values
:
d1 = {'key1': 'val1', 'key2': 'val2', 'key3': 'val3'} a, *b = d1.values() print(a) print(b) #val1 #['val2', 'val3']
Для получения кортежей с ключами и значениями — метод items
:
d1 = {'key1': 'val1', 'key2': 'val2', 'key3': 'val3'} a, *b = d1.items() print(a) print(b) #('key1', 'val1') #[('key2', 'val2'), ('key3', 'val3')]
Распаковка кортежей без переменных
d = 5, 10 print(*d) #5 10
Зачем это вообще может понадобиться?
К примеру, нам нужно получить числовой диапазон из значений кортежа.
Создадим кортеж из двух значений:
d = 5, 10 print(d) #(5, 10)
Если мы в функцию range()
передадим кортеж d
, то получим ошибку:
d = 5, 10 print(range(d)) #TypeError: 'tuple' object cannot be interpreted as an integer
Поскольку range()
ожидает в качестве аргументов 2 значения, а не кортеж из двух значений.
Но мы можем распаковать кортеж с помощью оператора *
:
d = 5, 10 print(range(*d)) #range(5, 10)
Преобразовав в список, получим числовой диапазон из переданного кортежа:
d = 5, 10 print(list(range(*d))) #[5, 6, 7, 8, 9]
Или таким образом:
d = 5, 10 print([*range(*d)]) #[5, 6, 7, 8, 9]
Распаковка словарей
d = {'key1': 'val1', 'key2': 'val2', 'key3': 'val3'} print(*d) #key1 key2 key3
Мы получили ключи словаря.
А если использовать метод values
:
d = {'key1': 'val1', 'key2': 'val2', 'key3': 'val3'} print(*d.values()) #val1 val2 val3
Получим значения словаря.
Если же использовать метод items
:
d = {'key1': 'val1', 'key2': 'val2', 'key3': 'val3'} print(*d.items()) #('key1', 'val1') ('key2', 'val2') ('key3', 'val3')
Получим кортежи из ключей и значений словаря.
Распаковка списков
lst = [1, 2, 3, 4] print(*lst) #1 2 3 4
Объединение итерируемых объектов
С помощью оператора *
, можно не только распаковывать, но и объединять итерируемые объекты:
d = 5, 10 e = ('один', 'два', 'три') f = [True, False] print([*range(*d), *e, *f]) #[5, 6, 7, 8, 9, 'один', 'два', 'три', True, False]
Точно также объединение работает и с другими типами данных:
my_tuple = (1, 2, 3) print((0, *my_tuple, 4)) my_set = {1, 2, 3} print({0, *my_set, 4}) #(0, 1, 2, 3, 4) #{0, 1, 2, 3, 4}
Объединили в один список — числовой диапазон, кортеж и список.
Объединение двух словарей с помощью **
d1 = {'key1': 'val1', 'key2': 'val2'} d2 = {'key4': 'val4', 'key5': 'val5'} d3 = {**d1, **d2} print(d3) #{'key1': 'val1', 'key2': 'val2', 'key4': 'val4', 'key5': 'val5'}
В итоге получился словарь, который содержит элементы и первого и второго словаря.
Упаковка в функциях
Операторами *
и **
также удобно пользоваться и в функциях. Это дает возможность вызывать функцию с произвольным количеством позиционных аргументов и именованных аргументов.
def my_function(*args, **kwargs): print(args) print(kwargs) my_function(1, 2, 3, a=10, b=20) #(1, 2, 3) #{'a': 10, 'b': 20}
После вызова функции мы получили кортеж args
позиционных аргументов и словарь kwargs
именованных аргументов.