История вопроса
Функция zip() появилась в Python как удобный способ "сшивать" несколько последовательностей в кортежи с соответствующими элементами, получая своеобразную "матричную" структуру.
Проблема
Ошибка возникает, когда разработчики применяют zip для последовательностей разной длины, ожидая, что результат будет по самой длинной, либо неправильно используют распаковку при обратном преобразовании.
Решение
zip() принимает одну или несколько последовательностей, возвращая итератор кортежей, где n-й кортеж содержит n-е элементы из всех последовательностей. Итерация заканчивается при исчерпании самой короткой последовательности.
Пример кода:
names = ['John', 'Anna', 'Peter'] ages = [28, 22, 35] grouped = list(zip(names, ages)) print(grouped) # [('John', 28), ('Anna', 22), ('Peter', 35)]
Ключевые особенности:
Что произойдет, если zip передать последовательности разной длины?
Результат будет длины самой короткой последовательности. Остальные элементы будут проигнорированы.
zip([1,2,3], ['a','b']) # [(1,'a'), (2,'b')]
Можно ли "развернуть" zip? Как получить обратно исходные последовательности?
Да, с помощью звёздочки-распаковки и zip(*iterator):
pairs = [(1, "a"), (2, "b")] numbers, letters = zip(*pairs) print(numbers) # (1, 2)
Чем отличается zip от itertools.zip_longest?
zip_longest из itertools работает до самой длинной последовательности, заполняя пропуски указанным fillvalue.
from itertools import zip_longest zip_longest([1,2], ['a','b','c'], fillvalue=None) # [(1,'a'), (2,'b'), (None, 'c')]
Обрабатывали пары пользователей и паролей через zip, но списки оказались разной длины. Несколько пользователей не были учтены из-за работы zip по короткому списку.
Плюсы:
Минусы:
Для объединения результатов теста и имен студентов применили zip_longest с fillvalue="n/a", сохранив данные по всем участникам.
Плюсы:
Минусы: