Функция zip. Примеры использования

Курс по Python: https://stepik.org/course/100707

На прошлых занятиях мы с вами познакомились с двумя функциями map() и filter(). На этом продолжим эту тему и поговорим о третьей часто применяемой функции:

zip(iter1 [, iter2 [, iter3] ...])

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

Давайте в качестве простого примера возьмем два списка со значениями:

a = [1, 2, 3, 4]
b = [5, 6, 7, 8, 9, 10]

и передадим их в качестве аргументов функции zip():

z = zip(a, b)
print(z)

После запуска программы увидим, что переменная z ссылается на объект zip. Как вы уже догадались, это итератор, элементы которого перебираются функцией next():

print(next(z))
print(next(z))

Давайте переберем все пары через цикл for:

for x in z:
    print(x)

Здесь x является кортежем из соответствующих значений списков a и b. Причем последняя пара заканчивается числами (4, 8), когда функция zip() дошла до конца самого короткого списка.

Также всегда следует помнить, что функция zip() возвращает итератор. Это значит, что перебрать элементы можно только один раз. Например, повторный вызов оператора for для этой же функции:

for x in z:
    print(x)

ничего не возвратит, так как мы уже один раз прошлись по его элементам в предыдущем цикле.

Если нам все же нужно несколько раз обходить выделенные пары элементов, то их следует вначале преобразовать, например, в кортеж:

z = tuple(zip(a, b))

А, затем, обходить несчетное число раз. Но в этом случае увеличивается расход памяти, так как мы сохраняем все элементы в кортеже, а не генерируем «на лету» с помощью итератора. Так что, без особой необходимости делать преобразование к кортежу или списку не стоит.

В качестве перебираемых коллекций могут быть любые итерируемые объекты, например, строки. Если мы добавим строку:

c = "python"

и вызовем функцию zip() и с ней:

z = zip(a, b, c)

то в консоли увидим кортежи уже из трех значений, причем последнее будет соответствующим символом строки. Также, напомню, что оператор for можно записать с тремя переменными, если перебираемые значения являются кортежами:

for v1, v2, v3 in z:
    print(v1, v2, v3)

Иногда удобно кортеж сразу распаковать в отдельные переменные и использовать внутри цикла for.

Также все кортежи из функции zip() мы можем получить с помощью распаковки, используя запись:

z1, z2, z3, z4 = zip(a, b, c)
print(z1, z2, z3, z4, sep="\n")

Здесь неявно вызывается функция next() для извлечения всех элементов. Или, можно записать так:

z1, *z2 = zip(a, b, c)
print(z1, z2, sep="\n")

Тогда первое значение будет помещено в переменную z1, а все остальные – в список z2.

И в заключение этого занятия я покажу вам  еще одно интересное преобразование, которое можно выполнить с помощью функции zip(). Если преобразовать итератор в список:

z = zip(a, b, c)
lz = list(z)

а, затем, распаковать его элементы с помощью оператора *:

print(*lz)

то мы получим уже не список, а четыре кортежа, следующих друг за другом. Если передать их в таком виде на вход функции zip():

t1, t2, t3 = zip(*lz)
print(t1, t2, t3, sep="\n")

то на выходе будут сформированы три кортежа из соответствующих элементов этих четырех. Вообще, это эквивалентно записи:

t1, t2, t3 = zip((1, 5, 'p'), (2, 6, 'y'), (3, 7, 't'), (4, 8, 'h'))

Но те же самые кортежи мы можем получить гораздо проще, если распаковать непосредственно итератор z:

t1, t2, t3 = zip(*z)

Как видите, к итератору вполне применим оператор распаковки элементов и на практике иногда этим пользуются.

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

Курс по Python: https://stepik.org/course/100707

Видео по теме