Что такое list comprehensions

Основы Python — кратко. Часть 4. Генераторы списков

List comprehensions

Продолжим наш цикл уроков. Добрый день.

Генерация списков (не знаю как адекватно перевести на русский list comprehensions) — яркий пример «синтаксического сахара». То есть конструкции, без которой легко можно обойтись, но с ней намного лучше 🙂 Генераторы списков, как это не странно, предназначены для удобной обработки списков, к которой можно отнести и создание новых списков, и модификацию существующих.
Допустим, нам необходимо получить список нечетных чисел, не превышающих 25.
В принципе, только познакомившись с работой команды xrange решить эту проблему несложно.

В общем-то, полученный результат — целиком нас устраивает всем, кроме длинной записи. тут-то на помощь и придет наш «сахарок». В самом простом виде, он обычно

Синтаксис, в принципе прост. Все выражение записывается в квадратных скобках. Сначала идет выражение, которое будет задавать элементы списка, потом — цикл с помощью которого можно изменять выражение. Обе части могут быть сколь угодно сложными. Например, вот как можно получить список квадратов тех же нечетных чисел:

По желанию, можно добавить дополнительные условия фильтрации. Например, доработаем наш предыдущий пример так, чтобы исключались квадраты чисел, кратных 3.

Вот пример немного посложнее.

Тут мы использовали генератор списков для превращения словаря в набор записей, это может быть удобно в таких задачах как сохранение конфигов или генерация HTML. Выражение «%s = %d» % (name, salary) — предназначено для форматирования строк, и по сути похоже на аналоги в С. В начале идет строка где задаются позиции для вставки значений (%s — строковое, %d — числовое). После знака % — «вставляемые» значения в виде кортежа.

В принципе — генератором можно обрабатывать и готовые списки.

Рассмотрим простой пример. Допустим, у нас имеется лог-файл, в котором хранится статистика запросов к серверу в виде «ip bytes» через пробел, по одному хосту на
строку. Примерно так:

Нам необходимо вычислить суммарный объем траффика на каждый хост и выдать его в виде списка в поряке убывания траффика.
Программу для решения данной проблемы будет весьма недлинной 🙂 Ее можно еще сильнее сократить, но это явно пойдет в ущерб ее читабельности.

Разберем ее пошагово.
1. В этой строке мы читаем из файла, который открываем с помощью функции open. Функция open по-умолчанию открывает файл для чтения и возвращает файловый объект, который кроме всего прочего является итерируемым. То есть по нему можно «двигаться» с помощью цикла for, чем мы и пользуемся в нашем случае. Кроме того, с помощью метода split мы делим каждую строку на пару — адрес — траффик.
2. Для удобства, мы формируем хеш, ключами в котором являются адреса, а значениями — траффик. Если ключа еще нет, то мы его созадаем, если же есть, то мы плюсуем текущий траффик к его предыдущим «наработкам». После этого цикла мы получим хеш с суммами траффика по всем хостам.
3. К сожалению, словари в Пайтоне не сортируются. Потому нам придется перевести его в список для сортировки. Следующие две строки переводят словарь в список и осуществляют его сортировку по второму полю.
4. Вот и все что осталось — «собрать» результат, как мы уже это делали раньше.

На сегодня хватит 🙂
Домашнее задание.
1. Реализовать функцию-генератор строки с таблицей умножения на число Х.
2. Есть лог-файл какого-то чата. Посчитать «разговорчивость» пользователей в нем в виде ник — количество фраз. Посчитать среднее число букв на участника чата.

ЗЫ О чем лучше продолжать — про классы и ООП или про элементы функционального программирования?

Источник

Когда использовать List Comprehension в Python

Перевод статьи «When to Use a List Comprehension» in Python, опубликованный сайтом webdevblog.ru.

Прим. переводчика: В русской терминологии нет общепризнанного перевода list comprehension. Гугл его переводит как списковое включение или абстракция списков. Хотя наиболее часто можно встретить фразу генератор списков, но мне кажется, это не совсем правильно, так как в Python есть отдельное понятие генератора. По-моему, наиболее подходящий перевод — представление списков. Поэтому в этой статье эта фраза будет использоваться без перевода, либо будет переводится следующим образом: list comprehension представление списков, set comprehension представление множества и dictionary comprehension представление словаря).

Содержание

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

К концу этого урока вы поймете всю мощь list comprehensions в Python и то, как насколько они удобны в использовании. Вы также получите представление о компромиссах, связанных с его использованием, чтобы вы могли понимать, когда другие подходы являются более предпочтительными.

В этом уроке вы узнаете, как:

Как создаются списки в Python

Чтобы лучше понять компромиссы, связанные с использованием list comprehension, давайте сначала рассмотрим способы создания списков.

Использование цикла for

Использование объектов map()

map() предоставляет альтернативный подход, основанный на функциональном программировании. Мы передаем функцию и итерируемый объект (iterable), а map() создает объект. Этот объект содержит выходные данные, которые мы получаем при запуске каждого итерируемого элемента через предоставленную функцию.

Немного запутано, поэтому давайте рассмотрим пример. Допустим, нам надо рассчитать цену после вычета налога для списка транзакций:

Использование List Comprehensions

List comprehensions — это третий способ составления списков. При таком элегантном подходе мы можем переписать цикл for из первого примера всего в одну строку кода:

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

Каждое представление списков в Python включает три элемента:

Единственное различие между этой реализацией и map() состоит в том, что list comprehension возвращает список, а не объект map.

Преимущества использования представления списков

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

Python включает в себя простые и мощные инструменты, которые вы можете использовать в самых разных ситуациях. И именно поэтому list comprehension считаются Pythonic.

List comprehensions также более декларативны, чем циклы. Это означает, что их легче читать и понимать. Циклы требуют, чтобы вы фокусировались на создании списка. Вам нужно вручную создать пустой список, зациклить элементы и добавить каждый из них в конец списка. Используя представления списков, вы можете вместо этого сосредоточиться на том, что хотите добавить в список, и положиться на то, что Python сам позаботится о его построении.

Что такое list comprehensions. Смотреть фото Что такое list comprehensions. Смотреть картинку Что такое list comprehensions. Картинка про Что такое list comprehensions. Фото Что такое list comprehensions

Погружаемся в Comprehensions

Чтобы понять всю ценность list comprehensions, полезно понять диапазон их функционала. Мы также коснемся изменений, которые были внесены в Python 3.8.

Использование условной логики

Вы уже видели этот шаблон для создания представлений списка:

Хотя этот шаблон точен, он также немного неполон. Более полное описание шаблона добавляет поддержку необязательных условных выражений. Наиболее распространенный способ добавить условную логику к list comprehension — добавить в конец условное выражение:

Здесь наше условное утверждение предшествует закрывающей скобке.

Условные выражения позволяют отфильтровывать нежелательные значения без вызова filter() :

В этом блоке кода условный оператор отфильтровывает в sentence любые символы, не являющиеся гласными.

Условие может содержать любое допустимое выражение. Если вам нужен более сложный фильтр, вы можете даже переместить условную логику в отдельную функцию:

Здесь мы создаем сложный фильтр is_consonant() и передаем эту функцию как условный оператор для нашего представления списка. Обратите внимание, что значение элемента i также передается в качестве аргумента нашей функции.

Для простой фильтрации условие можно поместить в конец оператора. Но что, если вы хотите не отфильтровать элемент, изменить его значение? В этом случае полезно поместить условное выражение в начало выражения:

С помощью этого шаблона вы можете использовать условную логику для выбора из нескольких возможных вариантов вывода. Например, если у вас есть список цен, вы можете заменить отрицательные цены на 0 и оставить положительные значения без изменений:

Использование Set и Dictionary Comprehensions

Представления списков в Python используются очень часто. Но это не единственный тип представлений. Вы также можете создавать представления множеств и словарей (set comprehension и dictionary comprehension). set comprehension почти ничем не отличается от представления списка. Разница лишь в том, что заданные значения обеспечивают, чтобы выходные данные не содержали дубликатов. Вы можете создать set comprehension, используя фигурные скобки вместо квадратных:

Dictionary comprehension похоже на set comprehension, но с дополнительным требованием определения ключа:

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

Python 3.8 представил выражение присваивания (assignment expression), также известное как оператор walrus (оператор моржа). Чтобы понять, как он используется, рассмотрим следующий пример.

Скажем, нам нужно сделать десять запросов к API, который будет возвращать данные о температуре. Мы хотим вернуть только результаты, превышающие 100 градусов по Фаренгейту. Предположим, что каждый запрос будет возвращать разные данные. В этом случае мы не сможем использовать list comprehension для решения проблемы. Формула expression for member in iterable (if conditional) не позволяет условию назначить данные переменной, к которой может обращаться это выражение.

Оператор walrus решает эту проблему. Он позволяет нам запускать выражение, одновременно назначая выходное значение переменной. Следующий пример показывает, как это возможно, путем использования get_weather_data() для генерации поддельных данных о погоде:

Не так часто возникает необходимость использовать выражение присваивания внутри list comprehension, но это полезный инструмент, который может быть в вашем распоряжении, когда это необходимо.

Что такое list comprehensions. Смотреть фото Что такое list comprehensions. Смотреть картинку Что такое list comprehensions. Картинка про Что такое list comprehensions. Фото Что такое list comprehensions

Когда не использовать List Comprehension в Python

Представления списков полезны и могут помочь нам написать элегантный код, который легко читать и отлаживать. Но это не всегда является правильным выбором. Представления могут замедлить работу вашего кода или привести к большему использованию памяти. Если из-за list comprehensions код станет менее производительным или более сложным для понимания, то, вероятно, лучше выбрать альтернативный вариант.

Остерегайтесь вложенных Comprehensions

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

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

Внешнее представление списка [… for _ in range(6)] создает шесть строк, в то время как внутреннее представление списка [i for i in range(5)] заполняет каждую из этих строк значениями.

До сих пор цель каждого вложенного представления была довольно интуитивна. Однако существуют другие ситуации, такие как выравнивание вложенных списков, когда логика, возможно, делает ваш код более запутанным. Давайте рассмотрим пример, где представление вложенного списка используется для выравнивания матрицы:

Код для выравнивания матрицы является лаконичным, оно, возможно, не очень интуитивно понятно. С другой стороны, если бы вы использовали цикл for для выравнивания одной и той же матрицы, ваш код был бы намного проще:

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

Хотя вложенные однострочные представления списков могут показаться более Pythonic, самое важное — это написать код, который ваша команда сможет легко понять и изменить. Выбирая свой подход, нужно ориентироваться на собственное суждение о том, не ухудшает ли представление списка читабельность вашего кода.

Используйте Генераторы для больших наборов данных

Представление списков в Python работает путем загрузки всего списка в память. Для небольших или даже средних списков это обычно хорошо. Например, если вы хотите сложить квадраты первой тысячи целых чисел, то list comprehension решит эту проблему превосходно:

Но что, если вы хотите сложить квадраты первых миллиардов целых чисел? Если вы попытаетесь это выполнить на своем компьютере, вы увидите, что ваш компьютер перестал отвечать на запросы. Это потому, что Python пытается создать список с одним миллиардом целых чисел, а это потребляет больше памяти, чем хотелось бы вашему компьютеру. Ваш компьютер может не иметь ресурсов, необходимых для создания огромного списка и сохранения его в памяти.

Когда размер списка становится проблематичным, зачастую полезнее использовать генератор вместо list comprehension. Генератор не создает единую большую структуру данных в памяти, а вместо этого возвращает итерацию. Ваш код будет запрашивать следующее значение из итерируемого объекта столько раз, сколько необходимо, или пока вы не достигните конца своей последовательности, сохраняя при этом только одно значение за раз.

Если бы вы суммировали первый миллиард квадратов с генератором, то работа вашей программы, вероятно, заняла бы некоторое время, но она не вызвала бы зависание вашего компьютера. В приведенном ниже примере используется генератор:

То, что это — генератор, видно по тому, что выражение не заключено в квадратные или фигурные скобки. При желании генераторы могут быть заключены в круглые скобки.

Приведенный выше пример все еще требует много времени для выполнения, но программа не зависнет, так как операции выполняются отложено. Из-за отложенных вычислений значения рассчитываются только по явному запросу. После того, как генератор выдаст значение (например, 567 * 567), он может добавить это значение к текущей сумме, затем отбросить это значение и сгенерировать следующее (568 * 568). Когда функция sum запрашивает следующее значение, цикл начинается заново. Для этого процесса необходим небольшой объем памяти.

map() также работает отложено, а значит, если вы решите использовать ее в этом случае, память не будет проблемой:

Профилирование для оптимизации производительности

Итак, какой подход быстрее? Стоит ли использовать списки или одну из их альтернатив? Вместо того, чтобы придерживаться единого правила на все случаи жизни, лучше спросить себя, имеет ли значение производительность в ваших конкретных обстоятельствах. Если нет, то обычно лучше выбрать подход, который приведет к чистому коду!

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

Заключение

В этом посте вы узнали, как использовать list comprehension в Python для выполнения сложных задач без чрезмерного усложнения кода.

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

Помните, что хотя list comprehensions привлекает к себе большое внимание, ваша интуиция и способность использовать расчетные данные, помогут вам написать чистый код, который выполняет поставленную задачу. Это, в конечном счете, ключ к созданию кода в духе Python!

Источник

List Comprehensions в Python за 5 минут

Зачем нужен list comprehension в Python?

Что такое list comprehensions. Смотреть фото Что такое list comprehensions. Смотреть картинку Что такое list comprehensions. Картинка про Что такое list comprehensions. Фото Что такое list comprehensions

Apr 11, 2019 · 4 min read

Чтобы сохранить строчки кода.

List comprehensions — это один из способов создания Pythonic-однострочников (one-liners) с итерируемыми списками.

В качестве примера рассмотрим продуктовую корзину. Вы вытаскиваете каждый товар и кладете на кассу. В таком случае, продуктовую корзину можно назвать iterable.

Разберем этот пример с помощью кода. Мы находимся в вычислительном магазине, поэтому будем покупать только числа.

Какие действия были выполнены?

Как выполнить эти действия с list comprehension?

Что происходит здесь?

Те же самые действия, написанные другим способом. Сравним.

Что такое list comprehensions. Смотреть фото Что такое list comprehensions. Смотреть картинку Что такое list comprehensions. Картинка про Что такое list comprehensions. Фото Что такое list comprehensions

Мы выполнили те же самы е действия на одной строке кода, вместо трех. В случае, если проект Python занимает 1000 строк, его можно сократить до 300. Однако подобные сокращения можно выполнить не всегда. Это просто пример выполнения аналогичных действий с Pythonic-однострочником.

Что еще можно сделать с помощью list comprehensions в Python?

Рассмотрим еще несколько примеров.

cashier_3 работает только с четными числами. Как это изменить?

С помощью conditional, который выполняет действие при значении True и останавливается при False.

Как будет выглядеть код с list comprehension?

Что здесь происходит?

Что такое list comprehensions. Смотреть фото Что такое list comprehensions. Смотреть картинку Что такое list comprehensions. Картинка про Что такое list comprehensions. Фото Что такое list comprehensions

Этот пример аналогичен предыдущему, только conditional выделен желтым.

Числа больше 100 и нечетные числа

cashier_4 принимает только числа больше 100 и нечетные числа. Как это выполнить?

Пример с list comprehension.

Что дальше?

Это руководство затрагивает лишь основы list comprehensions в Python. Научившись работать с ними, вы поймете, насколько большое значение они имеют при написании краткого и эффективного Python кода.

Источник

Когда использовать List Comprehension в Python

Перевод оригинальной статьи: James TimminsWhen to Use a List Comprehension in Python

Прим. переводчика: В русской терминологии нет общепризнанного перевода list comprehension. Гугл его переводит как списковое включение или абстракция списков. Хотя наиболее часто можно встретить фразу генератор списков, но мне кажется это не совсем правильно, так как в Python есть отдельное понятие генератора. По моему, возможно наиболее подходящий перевод был бы представление списков. Поэтому в этой статье эта фраза будет использоваться без перевода, либо будет переводится следующим образом: list comprehension представление списков, set comprehension представление множества и dictionary comprehension представление словаря)

Содержание

Спонсор поста ХОСТИНГ FOZZY БЫСТРЕЕ БЫСТРОГО
https://fozzy.com/ru/
Fozzy — компания, созданная профессионалами хостинг-индустрии, в рамках холдинга XBT — одного из мировых лидеров хостинга, представленного по всему миру: США, Нидерланды, Люксембург, Россия, Сингапур, Индия.
Fozzy работает честно и открыто. Мы не продаем волшебные «безлимитные тарифы» и «заоблачные возможности». Информация о наших серверах, технологиях и дата-центрах открыта для всех.

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

К концу этого урока вы поймете всю мощь list comprehensions в Python и то, как он удобен в использование. Вы также получите представление о компромиссах, связанных с его использованием, чтобы вы могли понимать, когда другие подходы являются более предпочтительными.

В этом уроке вы узнаете, как:

Как создаются списки в Python

Существует несколько способов создания списков в Python. Чтобы лучше понять компромиссы связанные с использованием list comprehension, давайте сначала рассмотрим способы создания списков с помощью этих подходов.

Использование цикла for

Наиболее распространенным типом цикла является цикл for. Использование цикла for можно разбить на три этапа:

Допустим на надо создать список squares, то эти шаги будут в трех строках кода:

Здесь мы создаем пустой список squares. Затем используем цикл for для перебора range(10). Наконец умножаем каждое число отдельно и добавляете результат в конец списка.

Использование объектов map()

map() предоставляет альтернативный подход, основанный на функциональном программировании. Мы передаем функцию и итерируемый объект (iterable), а map() создаст объект. Этот объект содержит выходные данные, которые мы получаем при запуске каждого итерируемого элемента через предоставленную функцию.

Немного запутано, поэтому в качестве примера рассмотрим ситуацию, в которой необходимо рассчитать цену после вычета налога для списка транзакций:

Здесь у вас есть итерируемый объект txns (в нашем случае простой список) и функция get_price_with_tax(). Мы передаем оба этих аргумента в map() и сохраняем полученный объект в final_prices. Мы можем легко преобразовать этот объект map в список, используя list().

Использование List Comprehensions

List comprehensions — это третий способ составления списков. При таком элегантном подходе мы можем переписать цикл for из первого примера всего в одну строку кода:

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

Каждое представление списков в Python включает три элемента:

Поскольку требования к expression (выражению) настолько гибки, представление списков хорошо работает во многих местах, где вы будете использовать map(). Вы так же можем переписать пример ценообразования:

Единственное различие между этой реализацией и map() состоит в том, что list comprehension возвращает список, а не объект map.

Преимущества использования представления списков

Представление списков часто описываются как более Pythonic, чем циклы или map(). Но вместо того, чтобы слепо принимать эту оценку, стоит понять преимущества использования list comprehension по сравнению с альтернативами. Позже вы узнаете о нескольких сценариях, в которых альтернативы являются лучшим выбором.

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

Это основная причина, почему list comprehension считаются Pythonic, поскольку Python включает в себя простые и мощные инструменты, которые вы можете использовать в самых разных ситуациях. Дополнительным преимуществом является то, что всякий раз, когда вы используете представления списков, вам не нужно запоминать правильный порядок аргументов, как при вызове map().

List comprehensions также более декларативны, чем циклы, что означает, что их легче читать и понимать. Циклы требуют, чтобы вы сосредоточились на создание списока. Вы должны вручную создать пустой список, зациклить элементы и добавить каждый из них в конец списка. Используя представления списков, вы можете вместо этого сосредоточиться на том, что хотите добавить в список, и положиться, на то что Python позаботится о том, как происходит построение списка.

Погружаемся в Comprehensions

Чтобы понять всю ценность, которую могут предоставить list comprehensions, полезно понять их диапазон возможных функций. Мы также коснемся изменений, которые были внесены в Python 3.8.

Использование условной логики

Ранее вы видели это шаблон для создания представлений списка:

Хотя этот шаблон точен, он также немного неполон. Более полное описание шаблона добавляет поддержку необязательных условных выражений. Наиболее распространенный способ добавить условную логику к list comprehension — добавить условное выражение в конец выражения:

Здесь наше условное утверждение предшествует закрывающей скобке.

Условные выражения позволяют отфильтровывать нежелательные значения, без вызова filter():

В этом блоке кода условный оператор отфильтровывает любые символы в sentence, которые не являются гласными.

Условие может содержать любое допустимое выражение. Если вам нужен более сложный фильтр, вы можете даже переместить условную логику в отдельную функцию:

Здесь мы создаем сложный фильтр is_consonant() и передаете эту функцию как условный оператор для нашего представления списка. Обратите внимание, что значение элемента i также передается в качестве аргумента нашей функции.

Вы можете поместить условие в конец оператора для простой фильтрации, но что, если вы хотите изменить значение элемента вместо его фильтрации? В этом случае полезно поместить условное выражение в начале выражения:

С помощью этого шаблона вы можете использовать условную логику для выбора из нескольких возможных вариантов вывода. Например, если у вас есть список цен, вы можете заменить отрицательные цены на 0 и оставить положительные значения без изменений:

Здесь, наше выражение i содержит условный оператор, if i> 0 else 0. Это говорит Python выводить значение i, если число положительное, но менять i на 0, если число отрицательное. Если это окажется недостаточно, то может быть полезно рассматривать условную логику как свою отдельную функцию:

Теперь наш условный оператор содержится в get_price(), и вы можете использовать его как часть выражения вашего списка.

Использование Set и Dictionary Comprehensions

Хотя list comprehension в Python является распространенным инструментом, вы также можете создавать множественные и словарные представления (set and dictionary comprehensions). set comprehension почти точно такое же, как представление списка. Разница лишь в том, что заданные значения обеспечивают, чтобы выходные данные не содержали дубликатов. Вы можете создать set comprehension, используя фигурные скобки вместо скобок:

В нашем примере set comprehension выводит все уникальные гласные, которые он нашел в quote. В отличие от списков, наборы не гарантируют, что элементы будут сохранены в определенном порядке. Вот почему первым членом набора является a, хотя первый гласный в quote — i.

Dictionary comprehensions аналогично, с дополнительным требованием определения ключа:

Чтобы создать словарь квадратов, воспользуемся фигурными скобками (<>), а также парой ключ-значение (i: i * i) в своем выражении.

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

Python 3.8 представил выражение присваивания (assignment expression), также известное как оператор walrus (оператор моржа). Чтобы понять, как он используется, рассмотрим следующий пример.

Скажем, нам нужно сделать десять запросов к API, которое будет возвращать данные о температуре. Мы хотим вернуть только результаты, которые превышают 100 градусов по Фаренгейту. Предположим, что каждый запрос будет возвращать разные данные. В этом случае в Python нет способа использовать list comprehension для решения проблемы. Выражение шаблона expression for member in iterable (if conditional) не позволяет условию назначить данные переменной, к которой можно обращаться в выражение.

Оператор walrus решает эту проблему. Это позволяет нам запускать выражение, одновременно назначая выходное значение переменной. В следующем примере показано, как это возможно, используя get_weather_data() для генерации поддельных данных о погоде:

Не так часто возникает необходимость использовать выражение присваивания внутри list comprehension, но это полезный инструмент, который может быть в вашем распоряжении, когда это необходимо.

Когда не использовать List Comprehension в Python

Представления списков полезны и могут помочь нам написать элегантный код, который легко читать и отлаживать, но он не всегда является правильным выбором. Он может заставить ваш код работать медленнее или использовать больше памяти. Если наш код станет менее производительным или сложным для понимания, то, вероятно, лучше выбрать альтернативу.

Остерегайтесь вложенных Comprehensions

Comprehensions могут быть вложенными при создания комбинаций списков, словарей и наборов в коллекции. Например, скажем, климатическая лаборатория отслеживает высокую температуру в пяти разных городах в течение первой недели июня. Идеальной структурой данных для хранения этих данных может быть представление списка вложенное в представление словаря:

Мы создали внешнюю коллекцию temps как представление словаря. Выражение представляет собой пару ключ-значение, которая содержит еще одно comprehension. Этот код быстро сгенерирует список данных для каждого города в cities.

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

Внешнее представление списка [… for _ in range(6)] создает шесть строк, в то время как внутреннее представление списка [i for i in range(5)] заполняет каждую из этих строк значениями.

До сих пор цель каждого вложенного представления довольно интуитивна. Однако существуют другие ситуации, такие как выравнивание вложенных списков, когда логика, возможно, делает ваш код более запутанным. Возьмем этот пример, который использует представление вложенного списка для выравнивания матрицы:

Код для выравнивания матрицы является лаконичным, но, возможно, он не настолько интуитивно понятен, чтобы понять, как он работает. С другой стороны, если бы вы использовали цикл for для выравнивания одной и той же матрицы, то ваш код будет намного проще:

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

Хотя понимание вложенных списков из одной строки может показаться более Pythonic, самое важное — это написать код, который ваша команда сможет легко понять и изменить. Когда вы выбираете свой подход, вам нужно судить, основываясь на том, считаете ли вы, что представление помогает или ухудшает читабельность.

Используйте Генераторы для больших наборов данных

Представление списков в Python работает путем загрузки всего списка в память. Для небольших или даже средних списков это обычно хорошо. Например если вы хотите сложить квадраты первых тысячи целых чисел, то list comprehension решит эту проблему превосходно:

Но что, если вы хотите сложить квадраты первых миллиардов целых чисел? Если вы попытаетесь это выполнить на своем компьютере, вы сможете заметить, что ваш компьютер перестанет отвечать на запросы. Это потому, что Python пытается создать список с одним миллиардом целых чисел, который потребляет больше памяти, чем хотелось бы вашему компьютеру. Ваш компьютер может не иметь ресурсов, необходимых для создания огромного списка и сохранения его в памяти.

Когда размер списка становится проблематичным, часто полезно использовать генератор вместо list comprehension. Генератор не создает единую большую структуру данных в памяти, а вместо этого возвращает итерацию. Ваш код будет запрашивать следующее значение из итерируемого столько раз, сколько необходимо или пока вы не достигните конца своей последовательности, сохраняя при этом только одно значение за раз.

Если бы вы суммировали первый миллиард квадратов с генератором, то ваша программа, вероятно, будет работать некоторое время, но она не будет вызывать зависание вашего компьютера. В приведенном ниже примере используется генератор:

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

Приведенный выше пример все еще требует много времени для выполнения, но программа не зависнит так как операции выполняются отложено. Из-за отложенных вычислений значения рассчитываются только по явному запросу. После того, как генератор выдаст значение (например, 567 * 567), он может добавить это значение к текущей сумме, затем отбросить это значение и сгенерировать следующее значение (568 * 568). Когда функция sum запрашивает следующее значение, цикл начинается заново. Для этого процесса необходим небольшой объем памяти.

map() также работает отложено, что означает, что память не будет проблемой, если вы решите использовать ее в этом случае:

Вам решать, предпочитаете ли вы выражение генератора или map().

Профилирование для оптимизации производительности

Итак, какой подход быстрее? Стоит ли использовать списки или одну из их альтернатив? Вместо того, чтобы придерживаться единого правила, которое справедливо во всех случаях, более полезно спросить себя, имеет ли значение производительность в ваших конкретных обстоятельствах. Если нет, то обычно лучше выбрать подход, который приведет к чистому коду!

Если вы реализуете сценарии, где важна производительность, то обычно лучше профилировать различные подходы и смотреть на данные. timeit — полезная библиотека для определения времени выполнения кусков кода. Вы можете использовать timeit для сравнения времени выполнения map(), циклов и списков:

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

Как показывает код, наибольшее различие заключается в подходе на основе цикла и map(), причем выполнение цикла занимает на 50% больше времени. То, имеет ли это значение, зависит от потребностей вашего приложения.

Заключение

В этом посте вы узнали, как использовать list comprehension в Python для выполнения сложных задач без чрезмерного усложнения кода.

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

Помните, что хотя list comprehensions привлекает к себе большое внимание, ваша интуиция и способность использовать расчетные данные, помогут вам написать чистый код, который выполняет поставленную задачу. Это, в конечном счете, ключ к созданию вашего кода Pythonic!

Упражнение на закрепление

Использование представление списков в Python

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *