Разберем префиксные операторы *
и **
, которые ставятся перед переменными для распаковки или упаковки коллекций.
Кортеж можно распаковать в отдельные элементы:
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
именованных аргументов.
Содержание: