Как работает функция zip в Python и какие у неё ключевые аргументы
Что проверяют
Знаете ли вы, что zip ленивый и молча обрезает данные по самой короткой последовательности. В задачах с данными это частый источник незаметной порчи выборки, поэтому следом спрашивают про strict и zip_longest.
Как отвечать
Сигнатура: zip(*iterables, strict=False). Функция принимает любое число итерируемых объектов и возвращает итератор кортежей: первые элементы из каждого, затем вторые и так далее.
- ленивость: в Python 3
zipвозвращает итератор, а не список. Пройти по нему можно один раз, второйlist(z)вернёт пустой список; - разная длина: по умолчанию остановка на самой короткой последовательности без ошибки и предупреждения;
strict=True: появился в Python 3.10, бросаетValueError, если длины разошлись. Для пар «признаки и метки» или «ключи и значения» его стоит включать всегда;- *`itertools.zip_longest(iterables, fillvalue=None)
**: отдельная функция, идёт до самой длинной последовательности и заполняет пропускиfillvalue. У самогоzip` такого аргумента нет.
Полезные приёмы: dict(zip(keys, values)) собирает словарь, zip(*pairs) разворачивает список пар обратно в столбцы, for x, y in zip(df["a"], df["b"]) заметно быстрее iterrows(), хотя векторная операция в pandas или NumPy быстрее обоих. Для нарезки на пачки в Python 3.12 появился itertools.batched, раньше для этого использовали трюк zip(*[iter(seq)] * n), который молча теряет неполный хвост.
Где спотыкаются
Склеивают признаки и метки обычным zip, хотя после фильтрации одной из колонок длины уже разные. Ошибки нет, часть строк пропала, пары сдвинуты, и модель учится на мусоре. Лечится strict=True или явной проверкой длин.
Называют fillvalue аргументом zip. Он есть только у zip_longest.
Не учитывают, что при исчерпании одного итератора zip уже успел взять элемент из предыдущих. Если потом продолжить читать тот же итератор, одного значения в нём не окажется.