itertools.zip_longest()

Объединение итераторов с использованием функции itertools.zip_longest()

Модуль itertools является одной из самых мощных фич Python, предоставляющий эффективные функции, которые работают с итераторами, то есть создают объекты, по которым можно пройтись в цикле (for или while). Одной из таких полезных функций является itertools.zip_longest(). Эта функция позволяет объединять несколько итераторов, таких как списки или кортежи, в один итератор, заполняя "недостающие" значения, если итераторы имеют разную длину.

Функция itertools.zip_longest() принимает два или более итерируемых объекта и объединяет их в один итератор, состоящий из кортежей. Каждый кортеж содержит элементы из всех исходных итераторов, которые стоят на одной и той же позиции.

Основное отличие zip_longest() от встроенной функции zip() заключается в том, что zip_longest() продолжает объединение до самого длинного итератора, заполняя недостающие значения неким "заполнителем".

Синтаксис

itertools.zip_longest(*iterables, fillvalue=None)

Параметры:

  • *iterables - целевые итерируемые объекты, которые нужно совместить.
  • fillvalue (необязательно) - значение, которым будут заполнены пустующие позиции в случае разной длины итерируемых объектов. По умолчанию None.

Примеры использования

Простое объединение списков разной длины

import itertools

numbers = [1, 2, 3, 4]
letters = ['a', 'b', 'c']
result = itertools.zip_longest(numbers, letters)

for item in result:
    print(item)
    
# (1, 'a')
# (2, 'b')
# (3, 'c')
# (4, None)

Здесь zip_longest() продолжает работу до тех пор, пока не достигнет конца самого длинного итератора, заполняя недостающие значения None.

Использование параметра fillvalue

import itertools

numbers = [1, 2, 3, 4]
letters = ['a', 'b']
result = itertools.zip_longest(numbers, letters, fillvalue='empty')

for item in result:
    print(item)

# (1, 'a')
# (2, 'b')
# (3, 'empty')
# (4, 'empty')

Здесь мы заменили значение по умолчанию для fillvalue на строку 'empty', чтобы указать на отсутствующие элементы.

Объединение более двух итераторов

import itertools

numbers = [1, 2]
chars = ['a', 'b']
flags = [True, False, True]
result = itertools.zip_longest(numbers, chars, flags)

for item in result:
    print(item)

# (1, 'a', True)
# (2, 'b', False)
# (None, None, True)

Как видим, zip_longest() с легкостью справляется с объединением более двух итераторов.

Советы

  • Использование zip_longest() вместо zip(): Когда важно убедиться, что ни один элемент из длинных итераторов не будет утерян, zip_longest() будет предпочтительнее. Обычная функция zip() прекратит выполнение, как только закончится самый короткий итератор.
  • Выбор подходящего fillvalue: Осознанно подходите к выбору fillvalue. Это значение должно отличаться от возможных элементов итератора, чтобы его можно было легко идентифицировать как заполнитель.
  • Неожиданный None: Если вы не предоставите fillvalue, будет использован None. В некоторых случаях это может вызвать путаницу, особенно если None может быть нормальным значением в вашем итераторе.

Заключение

itertools.zip_longest() - это мощный инструмент для работы с итераторами разной длины, особенно когда важно сохранить все данные из каждого итератора. Однако его следует использовать осознанно, учитывая потребность в заполнителях и возможные последствия выбора fillvalue.

Эта функция может быть особенно полезна в обработке данных, когда вам нужно работать с несколькими потоками информации одновременно, а также в ситуациях, когда данные могут прийти в несинхронизированных потоках или батчах.

Содержание: