7 уровней использования функции zip в Python

Просмотры: 2388
Категория: Python
Создано: 16 февраля 2021
Тэги: Python

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

Например, пусть имеется 2х3 матрица, представленная в виде вложенного списка:


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

Популярный вопрос на собеседованиях по Python

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

Джуниор разработчики могут написать для этого несколько циклов for. Однако сениор разработчику для этого понадобится одна строчка кода:


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

Элегантно, не правда ли?

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

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

Уровень 0: Базовое использования функции Zip

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

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

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

Эта функция напоминает работу застёжки «молнии», не правда ли?

Уровень 1 . Меньше-больше итерируемых объектов за один раз

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

Если мы передадим один список в функцию zip, получим

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

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

Между прочем, если не передать ни одного аргумента в zip функцию, она просто вернёт пустой итератор.

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

Реальные данные не всегда чистые и полные, иногда мы вынуждены работать с неравными по длине итерируемыми объектами. По умолчанию, результат работы zip функции основан на самом коротком итерируемом объекте.

Как показано в коде выше, самый короткий список – это id, поэтому record содержит только два кортежа, а последние два лидера в списке leaders были проигнорированы.

Но что делать, если последние два лидера обидятся на нас, если мы их проигнорируем?

Python снова поможет нам. Существует другая функция в модуле itertools, которая называется zip_longest. Как говорит её имя, она является сестрой функции zip, а её результат основывается на самом длинном аргументе.

Давайте применим zip_longest для того, чтобы сгенерировать список record

Как говорилось выше, результат функции zip_longest основывается на самом длинном аргументе. Опциональный аргумент fillvalue, у которого значение по умолчанию None, может помочь нам заполнить потерянные значения.

Уровень 3. Обратная операция unzip

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

К сожалению, в Python нет функции unzip. Однако, если мы знакомы с приёмам работы со звёздочкой, «раззипирование» становится очень лёгкой задачей.

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

Если мы не хотим использовать «звёздную» технику, то тогда мы должны действовать так.

Уровень 4. Создание и обновление словарей с помощью функции zip

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

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

Указанный пример выше вообще не использует цикл for. Как это элегантно и «питонистично»!

Уровень 5. Использование функции zip в циклах for

Часто приходится обрабатывать много итерируемых объектов за один раз. Здесь функция zip вместе с циклом for может прийти нам на помощь.

Давайте рассмотрим следующий пример:

Есть ли более элегантный метод решить эту задачу?

Уровень 6. Получить транспонированную матрицу

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

Как получить транспонированную матрицу?

Так как мы уже знаем функцию zip, распаковывание с помощью одинарной звёздочки, и list comprehension, то однострочное решение становится почти очевидным

Вывод

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

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