Найти тему
Nuances of programming

9 Уровней применения функции zip в Python

Оглавление

Источник: Nuances of Programming

Введение

В Python есть несколько встроенных функций, которые делают код очень элегантным. Одна из них  —  функция zip . Но начинающим не всегда бывает понятно, как её использовать, и порой это приводит к ошибкам.

Например, возьмём матрицу 2*3, представленную вложенным списком:

matrix = [[1 , 2 , 3 ], [1 , 2 , 3 ]]

И попробуем ответить на распространённый на собеседованиях по Python вопрос:

«Как транспонировать эту матрицу?».

Junior developer в ответ напишет несколько циклов for , в то время как senior ограничится всего одной строчкой кода:

matrix_T = [list(i) for i in zip(*matrix)]

Элегантно, согласитесь.

Если это однострочное решение пока что непонятно, не стоит переживать: дальше в статье мы подробно рассмотрим принцип действия мощной функции zip на девяти уровнях использования с полезными советами и хитрыми приёмами.

Уровень 0: как функция zip используется обычно

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

Вот пример её применения для объединения двух списков:

id = [1 , 2 , 3 , 4 ]
leaders = ['Elon Mask' , 'Tim Cook' , 'Bill Gates' , 'Yang Zhou' ]
record = zip(id, leaders)

print (record)
# <zip object at 0x7f266a707d80>
print (list (record))
# [(1, 'Elon Mask'), (2, 'Tim Cook'), (3, 'Bill Gates'), (4, 'Yang Zhou')]

Здесь функция zip возвращает итератор кортежей, где i -й кортеж содержит i -й элемент из каждого списка.

Принцип работы напоминает обычную застёжку-молнию.

-2

Уровень 1: Zip работает с любым количеством итерируемых объектов

На самом деле функция zip в Python намного мощнее застёжки-молнии. Она имеет дело не с двумя, а с любым количеством итерируемых объектов одновременно.

Вот мы передаём в функцию zip один список:

А как насчёт трёх списков?

То есть неважно, сколько итерируемых объектов передаётся в функцию zip : она в любом случае работает как надо.

Кстати, если аргумента нет, функция zip возвращает пустой итератор.

Уровень 2: работа с неравными по длине аргументами

В реальности данные не всегда чистые и полные: иногда приходится иметь дело с неравными по длине итерируемыми объектами. По умолчанию результат функции zip берётся по длине самого короткого итерируемого объекта.

Так, в приведённом выше коде самый короткий список  —  это id . Поэтому record содержит только два кортежа, а два последних лидера в списке leaders были отброшены.

А что, если эти два последних лидера окажутся недовольны тем, как с ними поступили?

Python и здесь придёт на помощь. В модуле itertools есть функция zip_longest . Посмотрим, как с её помощью генерируется список record :

Результат функции zip_longest основывается на самом длинном её аргументе. Дополнительный аргумент fillvalue , чьё значение по умолчанию равно None , помогает заполнить недостающие значения.

Уровень 3: операция распаковывания

Если в предыдущем примере получить сначала record , то как распаковать его на отдельные итерируемые объекты?

К сожалению, в Python нет функции распаковывания. Но если воспользоваться хитрыми приёмами звёздочек, распаковывание превращается в очень простую задачу.

С помощью звёздочки здесь выполнена операция распаковки: распакованы все четыре кортежа из списка record .

Если не прибегать к технике звёздочек, то же самое делается следующим методом:

Уровень 4: Создание и обновление словарей

С помощью функции zip очень просто создавать или обновлять dict , задействуя отдельные списки. Есть два однострочных решения:

  • использование dict comprehension и zip ;
  • использование функции dict и zip .

В этом примере не используются циклы for . И насколько же элегантным он от этого становится, по-питоновски элегантным!

Уровень 5: функция zip вместо циклов for

Существует ещё один вариант применения, в котором функция zip заменяет цикл for ,  —  это работа с последовательными элементами одной коллекции. Например, имеется список из целых чисел и надо вычислить разницу между соседними числами.

Уровень 6: сортировка списков

Кроме того, с помощью zip выполняется сортировка двух связанных друг с другом списков:

Уровень 7: применение функции zip в циклах for

Типичный сценарий  —  когда имеешь дело с несколькими итерируемыми объектами одновременно. Функция zip показывает себя во всей красе, если задействовать её вместе с циклами for .

Продемонстрируем это на следующем примере:

Есть ли более элегантная реализация этого примера?

Уровень 8: транспонирование матрицы

Наконец, мы возвращаемся к распространённому на собеседованиях по Python вопросу:

«Как транспонировать матрицу?».

Теперь, когда мы уже имеем представление о функции zip , распаковывании с помощью звёздочки и list comprehensions , однострочное решение будет более чем очевидным:

matrix = [[1, 2, 3], [1, 2, 3]]
matrix_T = [list(i) for i in zip(*matrix)]
print(matrix_T)
# [[1, 1], [2, 2], [3, 3]]

Заключение

Функция zip в Python очень полезная и мощная. Правильное её использование помогает писать меньше кода, выполняя при этом больше операций. «Делай больше, используя меньше»  —  такова философия Python.

Читайте также:

Читайте нас в Telegram , VK

Перевод статьи Yang Zhou : 7 Levels of Using the Zip Function in Python