Python:Рецепты/Распаковка последовательности произвольной длины

Материал из Онлайн справочника
Перейти к навигации Перейти к поиску

Проверка/Оформление/Редактирование: Мякишев Е.А.


Распаковка последовательности произвольной длины

Задача

Необходимо распаковать N-элементов из итерируемого объекта, который может содержать больше N-элементов и избежать генерирования исключения "too many values to unpack"(слишком много значений для распаковки)

Решение

Для решения данной задачи используется "выражение со звездочкой"(*).

Пример

№1

Допустим у вас есть 15 значений, первое и последнее из которых необходимо проигнорировать, а по остальным посчитать среднее значение.

1 numbers = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
2 first, *middle, last = numbers
3 avg = sum(middle)/len(middle)

Результат:

1 >>> avg
2 8.0
3 >>> first
4 1
5 >>> last
6 15
7 >>> numbers
8 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]

№2

Допустим у вас есть записи о пользователях(имя, почта и произвольное количество номеров телефонов), в данном случае распаковка будет выглядеть следующим образом:

1 record = ['John', 'John@example.com', '777-888-999', '666-777-888', '123-456-789']
2 name, email, *phones = record

Результат:

1 >>> name
2 'John'
3 >>> email
4 'John@example.com'
5 >>> phones
6 ['777-888-999', '666-777-888', '123-456-789']

phones - будет всегда списком, даже если номеров нету вообще.

№3

Расширенная распаковка отлично подходит для распаковки итерируемых объектов неизвестной или произвольной длины. Очень часто эти объекты имеют известные элементы и шаблоны. Например - всё, что после 1 элемента это адреса электронной почты.

1 record = ['email', 'john@example.com', 'foo@example.com', 'bar@example.com', 'wiki@example.com', 'ass@example.com']
2 _, *emails = record

Результат:

1 >>> email
2 ['john@example.com', 'foo@example.com', 'bar@example.com', 'wiki@example.com', 'ass@example.com']

№4

Дана последовательность кортежей переменной длины, необходимо произвести итерацию по последовательности и обработать каждый кортеж:

 1 records = [
 2 	('num', 1,2,3),
 3 	('str', 'hello world!'),
 4 	('num', 4,5,6)
 5 ]
 6 
 7 def do_num(x,y,z):
 8 	print('num',x,y,z)
 9 
10 def do_str(s):
11 	print('str', s)
12 	
13 for t, *args in records:
14 	if t == 'num':
15 		do_num(*args)
16 	elif t == 'str':
17 		do_str(*args)

Результат:

1 num 1 2 3
2 str hello world!
3 num 4 5 6

№5

Распаковка со звездочкой может комбинироваться с операциями обработки строк, например разрезание:

1 txt = "john:user:1:1:5:john@example.com:/home/john"
2 name, *fields, email, homedir = txt.split(':')

Результат:

1 >>> name
2 'john'
3 >>> email
4 'john@example.com'
5 >>> homedir
6 '/home/john'

№6

При распаковке вам иногда необходимо отбросить значения, сделать это можно так:

1 p2 = ['WIKIHANDBK', 10, 100.9, (15, 4, 2020)]
2 name, *_, (*_, year) = p2

Результат:

1 >>> name
2 'WIKIHANDBK'
3 >>> year
4 2020

См.также

Ссылки на полезные ресурсы

Внешние ссылки