Функция zip для прохода по нескольким итерируемым объектам
Иногда нам нужно пройти по нескольким спискам в одном цикле и взять из них данные с одинаковых позиций. Допустим, у нас есть два списка:
name_hero = [ 'Hulk', 'Mr. Fantastic', 'Invisible Woman', 'Doctor Strange', 'Doctor Octopus', 'Spider-Man', ] name_real = [ 'Bruce Banner', 'Reed Richards', 'Sue Storm', 'Stephen Strange', 'Otto Octavius', 'Peter Parker', ]
И перед нами стоит задача обработать пары. К сожалению, в коде новичков часто можно встретить такие подходы:
# Так делать плохо for i in range(len(name_hero)): print(name_hero[i], '-', name_real[i]) # И так делать тоже плохо for i, nickname in enumerate(name_hero): print(nickname, '-', name_real[i])
Такой подход не укладывается в python-way. Поэтому есть встроенный инструмент, чтобы сделать это лучше:
for nickname, name in zip(name_hero, name_real): print(nickname, '-', name) # Все три цикла выведут одинаковый результат: Hulk - Bruce Banner Mr. Fantastic - Reed Richards Invisible Woman - Sue Storm Doctor Strange - Stephen Strange Doctor Octopus - Otto Octavius Spider-Man - Peter Parker
Давайте рассмотрим подробней, что мы получаем, когда используем
names_paired = list(zip(name_hero, name_real)) print(names_paired) # Результат: [('Hulk', 'Bruce Banner'), ('Mr. Fantastic', 'Reed Richards'), ('Invisible Woman', 'Sue Storm'), ('Doctor Strange', 'Stephen Strange'), ('Doctor Octopus', 'Otto Octavius'), ('Spider-Man', 'Peter Parker')]
Видим, что мы получили список из тюплов (кортежей), каждый из которых — пара из элементов обоих списков: первый с первым, третий с третьим и т. д., а в цикле мы распаковываем каждую пару в переменные
Однако помимо создания пар
names_unpaired = list(zip(*names_paired)) print(names_unpaired) # Получаем список из двух тюплов: [('Hulk', 'Mr. Fantastic', 'Invisible Woman', 'Doctor Strange', 'Doctor Octopus', 'Spider-Man'), ('Bruce Banner', 'Reed Richards', 'Sue Storm', 'Stephen Strange', 'Otto Octavius', 'Peter Parker')] # Распаковываем два тюпла new_name_hero, new_name_real = names_unpaired # И проверяем, что результаты равны исходным данным print('name_hero == new_name_hero:', tuple(name_hero) == new_name_hero) print('name_real == new_name_real:', tuple(name_real) == new_name_real) # В консоли получаем: name_hero == new_name_hero: True name_real == new_name_real: True
Это работает не только с парами, можно использовать необходимое количество аргументов:
first_appeared = [ 'The Incredible Hulk (May 1962)', 'The Fantastic Four #1 (Nov. 1961)', 'The Fantastic Four #1 (Nov. 1961)', 'Strange Tales #110 (July 1963)', 'The Amazing Spider-Man #3 (July 1963)', 'Amazing Fantasy #15 (August 1962)', ] for nickname, name, appeared in zip(name_hero, name_real, first_appeared): print(f'{nickname} [{name}]: {appeared}')
Получаем:
Hulk [Bruce Banner]: The Incredible Hulk (May 1962) Mr. Fantastic [Reed Richards]: The Fantastic Four №1 (Nov. 1961) Invisible Woman [Sue Storm]: The Fantastic Four №1 (Nov. 1961) Doctor Strange [Stephen Strange]: Strange Tales №110 (July 1963) Doctor Octopus [Otto Octavius]: The Amazing Spider-Man №3 (July 1963) Spider-Man [Peter Parker]: Amazing Fantasy №15 (August 1962)