Что такое list comprehension

Списковые включения (list comprehension)

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

Введение

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

Примеры

Замечания

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

Примеры списковых включений

Списковые включения

Также есть необязательное условие if:

Чтобы создать список квадратов целых чисел:

Помимо ускорения (как описано здесь), списковые включения примерно эквивалентны следующему циклу for:

Выражение, применяемое к каждому элементу, может быть настолько сложным, насколько это необходимо:

Условие Else

Обратите внимание, что здесь используется другая языковая конструкция, условное выражение, которое само по себе не является частью синтаксиса включения. Учитывая, что if после for…in является частью спискового включения и используется для фильтрации элементов из исходного кода.

Двойная итерация

Это может быть сжат в одну строку, как [str(x) for i in range(3) for x in foo(i)]

Встроенная мутация и другие побочные эффекты

Многие функции (особенно чистые функции) просто берут объект и возвращают какой-то объект. Встроенная функция изменяет существующий объект, это называется побочным эффектом. Другие примеры включают операции ввода и вывода, такие как print.

Вместо этого используйте:

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

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

Пробелы в списках

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

Избегайте повторяющихся и тяжёлых операций с использованием условий

Пример

Рассмотрим следующее списковое включение:

Или, используя эквивалентный map :

Другой способ, который может сделать код более читабельным — поместить частичный результат ( v в предыдущем примере) в итерацию (например, список или кортеж), а затем выполнить итерацию по нему. Поскольку v будет единственным элементом в итерации, в результате мы имеем ссылку на вывод нашей медленной функции, вычисляемой только один раз:

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

Другой способ предотвратить многократное вычисление f(x) — это использовать декоратор @functools.lru_cache() (Python 3.2+) для f(x). Поскольку вывод f для ввода x уже был вычислен один раз, второй вызов функции исходного спискового включения будет таким же быстрым, как поиск по словарю. Этот подход использует запоминание для повышения эффективности, что сравнимо с использованием выражений генератора.

Скажем, вы должны сгладить список

Одним из методов может быть:

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

Изменение типов в списке

Пример

Включения с участием кортежей

Пример

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

Это как обычный цикл for:

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

Подсчет вхождений с использованием включений

Пример

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

Основная концепция такова:

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

Словарь включений

Пример

Словарь включений аналогичен списковым включениям, за исключением того, что он создаёт объект словаря вместо списка.

это просто еще один способ написания:

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

Или переписать с помощью генераторного выражения.

Начиная со словаря и используя словарь в качестве фильтра пары ключ-значение

Переключение ключа и значения словаря (инвертировать словарь)

если вы хотели поменять местами ключи и значения, вы можете использовать несколько подходов в зависимости от вашего стиля кодирования:

Объединение словарей

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

Примечание: словарь включений был добавлен в Python 3.0 и перенесён в версию 2.7+, в отличие от списочных включений, которые были добавлены в 2.0. Версии dict() для имитации поведения словаря включений.

Генераторные выражения

Пример

Генераторное выражение очень похоже на списки. Основное отличие состоит в том, что оно не создаёт полный набор результатов сразу; он создаёт объект генератора, который затем может быть повторён.

Например, посмотрите различия в коде:

Примечание: В Python 3, range просто возвращает генератор. Для получения дополнительной информации см Различия между функциями дальности и xrange например.

Сценарии использования

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

Другим распространенным вариантом использования является недопущение итерации по всей итерации когда не требуется. В этом примере элемент извлекается из удаленного API с каждой итерацией get_objects() . Тысячи объектов могут существовать, должны быть найдены один за другим, и нам нужно только знать, существует ли объект, который соответствует шаблону. Используйте генераторное выражение, когда мы видим похожую задачу

Набор включений

Пример

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

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

Условные списки

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

Приведенный выше код эквивалентен:

Это становится более очевидным, если вы объедините его с другими операторами:

Приведенный выше код эквивалентен:

Можно комбинировать тройные выражения и if условия. Тернарный оператор работает с отфильтрованным результатом:

То же самое не могло быть достигнуто только одним троичным оператором:

Перечень списков с помощью вложенных циклов

Например, следующий код уплощение списка списков с использованием нескольких for операторов:

Можно эквивалентно записать в виде списка с кратной for конструкцией:

Как в расширенной форме, так и в понимании списка, внешний цикл (первый для оператора) идет первым.

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

Накладные расходы на вызов функции выше примерно 170ns.

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

Фильтр рефакторинга и map для отображения списка

В filter или map функция часто должна быть заменена списком. Гвидо ван Россум описывает это хорошо в открытом письме в 2005 году :

Следующие строки коды считаются «не рабочими» и будут вызывать ошибки.

Фильтр

Списковые включения с участием кортежей

for пункта в список понимания можно указать более одной переменные:

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

Подсчет вхождений

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

Основная концепция может быть обобщена как:

Изменение типов в списке

Понимание вложенного списка

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

Вложенный пример эквивалентен

Один пример, где вложенное списковое включение может быть использовано для транспонирования матрицы.

Итерация двух или более списков одновременно в пределах понимания списка

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

Научим основам Python и Data Science на практике

Это не обычный теоритический курс, а онлайн-тренажер, с практикой на примерах рабочих задач, в котором вы можете учиться в любое удобное время 24/7. Вы получите реальный опыт, разрабатывая качественный код и анализируя реальные данные.

Источник

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Что такое list comprehension. Смотреть фото Что такое list comprehension. Смотреть картинку Что такое list comprehension. Картинка про Что такое list comprehension. Фото Что такое list comprehensionПример non-list comprehension и list comprehension с conditional.

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

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

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

Пример с list comprehension.

Что дальше?

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

Источник

Когда использовать 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 comprehension. Смотреть фото Что такое list comprehension. Смотреть картинку Что такое list comprehension. Картинка про Что такое list comprehension. Фото Что такое list comprehension

Погружаемся в 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 comprehension. Смотреть фото Что такое list comprehension. Смотреть картинку Что такое list comprehension. Картинка про Что такое list comprehension. Фото Что такое list comprehension

Когда не использовать 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!

Источник

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

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