Генератор массивов python. Генераторы списков, словарей и множеств. Условные выражения в генераторах списков

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

Работа с файлами и каталогами

Python 3 поставляется с модулем os , что означает «операционная система». содержит множество функций для получения информации о локальных каталогах, файлах, процессах и переменных окружения (а в некоторых случаях, и для манипулирования ими). Python предлагает очень хороший унифицированный программный интерфейс для всех поддерживаемых операционных систем , так что ваши программы можно запускать на любом компьютере с минимальным количеством платформо-зависимого кода.

Текущий рабочий каталог

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

  1. Импортирование какого-либо модуля из папки примеров
  2. Вызов функции из этого модуля
  3. Объяснение результата

Всегда есть текущий рабочий каталог.

Если вы ничего не знаете о текущем рабочем каталоге, то, возможно, шаг 1 окажется неудачным и будет порождено исключение типа ImportError . Почему? Потому что Python будет искать указанный модуль в пути поиска оператора import , но не найдёт его, потому что каталог examples не содержится в путях поиска. Чтобы исправить это, вы можете сделать одно из двух:

  • либо добавить папку examples в путь поиска оператора import ;
  • либо сделать текущим рабочим каталогом папку examples .

Текущий рабочий каталог является неявным параметром, который Python постоянно хранит в памяти. Текущий рабочий каталог есть всегда, когда вы работаете в интерактивной оболочке Python, запускаете свой сценарии из командной строки или CGI -сценарий где-то на веб-сервере .

Модуль os содержит две функции для работы с текущим рабочим каталогом.

>>> import os

>>> print (os .getcwd () )
C:\Python31

>>> os .chdir ()

>>> print (os .getcwd () )

Работа с именами файлов и каталогов

Раз зашла речь о каталогах, я хочу обратить ваше внимание на модуль os .path . Он содержит функции для работы с именами файлов и каталогов.

>>> import os

>>> print (os .path .join ("/Users/pilgrim/diveintopython3/examples/" , "humansize.py" ) )
/Users/pilgrim/diveintopython3/examples/humansize.py

>>> print (os .path .join ("/Users/pilgrim/diveintopython3/examples" , "humansize.py" ) )
/Users/pilgrim/diveintopython3/examples\humansize.py

>>> print (os .path .expanduser ("~" ) )
c:\Users\pilgrim

>>> print (os .path .join (os .path .expanduser ("~" ) , "diveintopython3" , "examples" , "humansize.py" ) )
c:\Users\pilgrim\diveintopython3\examples\humansize.py

Модуль os .path также содержит функции для разбиения файловых путей, имён папок и файлов на их составные части.

>>> pathname = "/Users/pilgrim/diveintopython3/examples/humansize.py"

>>> os .path .split (pathname)
("/Users/pilgrim/diveintopython3/examples" , "humansize.py" )

>>> (dirname, filename) = os .path .split (pathname)

>>> dirname
"/Users/pilgrim/diveintopython3/examples"

>>> filename
"humansize.py"

>>> (shortname, extension) = os .path .splitext (filename)
>>> shortname
"humansize"
>>> extension
".py"

Получение содержимого каталога

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

Модуль glob - это ещё один инструмент из стандартной библиотеки Python. Это простой способ программно получить содержимое папки, а также он умеет использовать символы-джокеры , с которыми вы наверняка знакомы, если работали в командной строке.

>>> os .chdir ("/Users/pilgrim/diveintopython3/" )
>>> import glob

>>> glob .glob ("examples/*.xml" )
[ "examples\\ feed-broken.xml" ,
"examples\\ feed-ns0.xml" ,
"examples\\ feed.xml" ]

>>> os .chdir ("examples/" )

>>> glob .glob ("*test*.py" )
[ "alphameticstest.py" ,
"pluraltest1.py" ,
"pluraltest2.py" ,
"pluraltest3.py" ,
"pluraltest4.py" ,
"pluraltest5.py" ,
"pluraltest6.py" ,
"romantest1.py" ,
"romantest10.py" ,
"romantest2.py" ,
"romantest3.py" ,
"romantest4.py" ,
"romantest5.py" ,
"romantest6.py" ,
"romantest7.py" ,
"romantest8.py" ,
"romantest9.py" ]

Получение сведений о файле

Любая современная операционная система хранит сведения о каждом файле (метаданные): дата создания, дата последней модификации, размер файла и т. д. Python предоставляет единый программный интерфейс для доступа к этим метаданным. Вам не надо открывать файл; всё, что требуется - имя файла.

>>> import os

>>> print (os .getcwd () )
c:\Users\pilgrim\diveintopython3\examples

>>> metadata = os .stat ("feed.xml" )

>>> metadata.st_mtime
1247520344.9537716

>>> import time

>>> time .localtime (metadata.st_mtime )
time .struct_time (tm_year= 2009 , tm_mon= 7 , tm_mday= 13 , tm_hour= 17 , tm_min= 25 ,
tm_sec= 44 , tm_wday= 0 , tm_yday= 194 , tm_isdst= 1 )

Получение абсолютных путей

В предыдущем разделе функция glob .glob () возвращала список относительных путей. В первом примере пути имели вид "examples\feed.xml" , а во втором относительные пути были даже короче, например, "romantest1.py" . Пока вы остаётесь в текущем рабочем каталоге, по этим относительным путям можно будет открывать файлы или получать их метаданные. Но если вы захотите получить абсолютный путь - то есть тот, который включает все имена каталогов до корневого или до буквы диска, вам понадобится функция os .path .realpath () .

>>> import os
>>> print (os .getcwd () )
c:\Users\pilgrim\diveintopython3\examples
>>> print (os .path .realpath ("feed.xml" ) )

c:\Users\pilgrim\diveintopython3\examples\feed.xml

Генераторы списков

В генераторах списков можно использовать любые выражения Python.

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

>>> a_list = [ 1 , 9 , 8 , 4 ]
>>> [ elem * 2 for elem in a_list]
[ 2 , 18 , 16 , 8 ]

>>> a_list
[ 1 , 9 , 8 , 4 ]

>>> a_list = [ elem * 2 for elem in a_list]
>>> a_list
[ 2 , 18 , 16 , 8 ]

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

>>> import os , glob
>>> glob .glob ("*.xml" )
[ "feed-broken.xml" , "feed-ns0.xml" , "feed.xml" ]

>>> [ os .path .realpath (f) for f in glob .glob ("*.xml" ) ]
[ "c:,
"c:,
"c:]

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

>>> import os , glob

>>> [ f for f in glob .glob ("*.py" ) if os .stat (f) .st_size > 6000 ]
[ "pluraltest6.py" ,
"romantest10.py" ,
"romantest6.py" ,
"romantest7.py" ,
"romantest8.py" ,
"romantest9.py" ]

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

>>> import os , glob

>>> [ (os .stat (f) .st_size , os .path .realpath (f) ) for f in glob .glob ("*.xml" ) ]
[ (3074 , "c:\\ Users\\ pilgrim\\ diveintopython3\\ examples\\ feed-broken.xml" ) ,
(3386 , "c:\\ Users\\ pilgrim\\ diveintopython3\\ examples\\ feed-ns0.xml" ) ,
(3070 , "c:\\ Users\\ pilgrim\\ diveintopython3\\ examples\\ feed.xml" ) ]
>>> import humansize

>>> [ (humansize.approximate_size (os .stat (f) .st_size ) , f) for f in glob .glob ("*.xml" ) ]
[ ("3.0 KiB" , "feed-broken.xml" ) ,
("3.3 KiB" , "feed-ns0.xml" ) ,
("3.0 KiB" , "feed.xml" ) ]

Генераторы словарей

Генератор словаря похож на генератор списка, но вместо списка он создает словарь.

>>> import os , glob

>>> metadata = [ (f, os .stat (f) ) for f in glob .glob ("*test*.py" ) ]

>>> metadata[ 0 ]
("alphameticstest.py" , nt.stat_result (st_mode= 33206 , st_ino= 0 , st_dev= 0 ,
st_nlink= 0 , st_uid= 0 , st_gid= 0 , st_size= 2509 , st_atime= 1247520344 ,
st_mtime= 1247520344 , st_ctime= 1247520344 ) )

>>> metadata_dict = { f:os .stat (f) for f in glob .glob ("*test*.py" ) }

>>> type (metadata_dict)
< class "dict" >

>>> list (metadata_dict.keys () )
[ "romantest8.py" , "pluraltest1.py" , "pluraltest2.py" , "pluraltest5.py" ,
"pluraltest6.py" , "romantest7.py" , "romantest10.py" , "romantest4.py" ,
"romantest9.py" , "pluraltest3.py" , "romantest1.py" , "romantest2.py" ,
"romantest3.py" , "romantest5.py" , "romantest6.py" , "alphameticstest.py" ,
"pluraltest4.py" ]

>>> metadata_dict[ "alphameticstest.py" ] .st_size
2509

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

>>> import os , glob , humansize

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

Person_data = ["John", "Smith", 23, "programmer"]

User_name, user_surname, user_age, user_occupation = person_data

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

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

Как пользоваться генераторами в Python.

Генераторами списков в Python называются однострочные конструкции, которые позволяют создавать новые списки.

Синтаксис генераторов списков такой:

# самый простой генератор new_list =

В итоге new_list будет содержать числа от 0 до 9. Понятно, что для того чтобы создать такой список незачем пользоваться генератором. Достаточно просто воспользоваться функцией range()

# пример посложнее word = "hello" new_list =

Теперь new_list будет выглядеть так:

["h","e","l","l","o"]

Так же в генераторы списков можно вставлять конструкцию if:

# Создаем список из чисел кратных трем new_list =

В итоге получим:

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

# создание колоды карт при помощи генератора списков # масти suits = "HDCS" # ранги ranks = "23456789TJQKA" # генерируем колоду deck =

Получим следующий результат:

Представьте, сколько времени мы сэкономили, написав всего одну строчку вместо нескольких циклов .

Как извлечь элементы из подсписков в Python.

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

Например имеем такой список:

Outer = [, , ]

Задача создать отдельный список содержащий все элементы подсписков данного списка. Выполнить эту задачу можно при помощи все того же генератора списков:

New_list =

Таким образом получаем список со всеми элементами:

На этом на сегодня все. Удачи в освоении Python !

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

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

>>> a = >>> for i in range(1,15): ... a.append(i) ... >>>

Список занял три строчки кода. А генератору нужна только одна:

>>> a = >>> a

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

  1. Что будем делать с элементов (в нашей ситуации не делаем ничего, просто вносим в перечень).
  2. Что будем брать (мы берем элемент i).
  3. Откуда будем брать (из объекта range). Для отделения частей используем ключевые слова in и for.

Разберем на примере

>>> a = >>> b = >>> b

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

  1. Делаем – возводим наш элемент в квадрат.
  2. Берем – элемент.
  3. Откуда – из перечня а.
>>> a = {1:10, 2:20, 3:30} >>> b = for i in a] >>> b

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

>>> a = {1:10, 2:20, 3:30} >>> b = [] for i in a] >>> b [, , ] >>> c = >>> c

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

>>> c = >>> for i in b: ... for j in i: ... c.append(j) ... >>> c

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

>>> a = "lsj94ksd231 9" >>> b =

Либо наполнить список цифрами, кратными 31 или 30:

>>> a = >>> a

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

Закончились деньги, а до зарплаты еще пара недель? Можно одолжить, но что делать если не у кого? Не идти же в банк за кредитом. В этом случае вам помогут микрозаймы . Простой зайдите на сайт, оформите заявку (это очень просто и быстро) и через несколько минут вы получите деньги! Очень удобно и быстро, и главное не нужно ни у кого просить!

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

Простая генерация

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

Следующий пример демонстрирует создание в Python списка чисел при помощи генератора. Переменная i является ссылкой на текущий элемент объекта data. Функция range здесь принимает два аргумента, которые устанавливают границы для сгенерированной последовательности целых чисел. Вывод информации на экран происходит через метод print.

>>> data = >>> print(data)

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

>>> data = >>> print(data) ["p", "y", "t", "h", "o", "n"]

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

Генератор с условием

Один из часто используемых способов генерации списков в Python - с условием. Предыдущие примеры демонстрировали довольно тривиальный подход к заполнению списка при помощи генератора. Данные конструкции языка Python позволяют задавать определенные условия для выполнения такой операции . Например, существует задача перенести в список только четные числовые значения из созданной ранее выборки range.

>>> data = >>> print(data)

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

Генератор с циклом

В языке Python также существует возможность генерировать список при помощи нескольких циклов , помещая их в квадратные скобки инициализации. В следующем примере используется две конструкции for, осуществляющие поочередный перебор значений для переменных i и j. Числовой диапазон для них (от 0 до 3), как и раньше, задается через методы range.

>>> data = >>> print(data)

Результатом выполнения данного кода станет создание списка data на основе поочередного перемножения переменных i и j. Благодаря циклам for, их значения увеличиваются пошагово. Таким образом, генерируется список из девяти элементов.

Генерация вложенных списков

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

>>> data = [ for j in range(0, 3)] >>> print(data) [, , ]

Данный код демонстрирует создание двумерной матрицы с размерностью 3×3 при помощи генератора двумерного списка Python. Элементами этой числовой последовательности стали цифровые значения из методов range, как и в предыдущих примерах. Переменные i и j пошагово увеличиваются в циклах на единицу и перемножаются между собой. Функция print служит для визуального отображения сгенерированного набора данных на экран компьютера.

Достаточно часто при создании вложенного списка Python используется генератор матрицы нулей. В качестве примера создадим матрице 3×2:

>>> data = [ for y in range(3)] >>> print(data) [, , ]

Генератор списка с lambda

Как известно, лямбда-функции в Python представляют собой некую операцию, возвращающую значение. Преимуществом данного механизма является возможность его применения внутри выражения. Это позволяет значительно уменьшить объем набираемого программистом кода, поскольку в таком случае нет необходимости отдельно объявлять новый метод . Генератор списка с lambda в Python позволяет

Иногда используются в Python lambda-функции в генераторе списков. В следующем примере будет создана новая последовательность чисел, полученных в результате выполнения метода range. Как и раньше, элемент этого набора представляется в виде переменной i, которая пошагово получает новые значения (от 0 до 9) в цикле for. Лямбда-функция принимает в качестве аргумента значение, затем перемножает его само на себя и возвращает обратно в генератор.

>>> data = [(lambda i: i*i)(i) for i in range(0, 10)] >>> print(data)

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

Применение itertools

Для выполнения продвинутой генерации списка в языке Python используется подключаемая библиотека под названием itertools. С ее помощью можно создавать наборы значений по определенным правилам. Чтобы активировать функции данного модуля, следует внести в начало программного файла следующую инструкцию .

Import itertools

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

>>> data = >>> print(data)

Как видно из полученного результата, метод возвращает последовательность одинаковых объектов (в данном случае это число 1), повторяющихся 5 раз.

Заключение

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

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

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

Res = for x in xrange(1, 25, 2): res.append(x) ... print res

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

Res = ... print res

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

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

Res = ... print res

Задание 6.1. Генератор списка

Нужно получить список двоичных чисел не являющихся квадратами.

Генераторы

Конструкции типа mylist = формируют списки элементов, значения которых хранятся в памяти. К ним можно применять конструкцию for i in mylist: print(i) для работы с элементами сколько угодно раз.

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

Mygenerator = (x*x for x in range(3)) for i in mygenerator: print(i)

Всё то же самое, разве что используются круглые скобки вместо квадратных. НО: нельзя применить конструкцию for i in mygenerator второй раз, так как генератор может быть использован только единожды: он вычисляет 0, потом забывает про него и вычисляет 1, завершая вычислением 4 - одно за другим. Также нельзя получить число элементов функцией len() . К генераторам нельзя применить срезы mygenerator . Но, генераторы позволяют сократить объем памяти для запуска программы.

Yield

Yield это ключевое слово, которое используется примерно как return - отличие в том, что функция вернёт генератор.

Def createGenerator() : mylist = range(3) for i in mylist: yield i*i mygenerator = createGenerator() # создаём генератор for i in mygenerator: print(i)

Задание 6.2. Генератор тетраэдрических чисел

При помощи генератора треугольных чисел создать генератор тетраэдрических чисел.

Задание 6.3. Генератор переливаний

Имеется школьная задача о получении нужного объема при помощи бесконечного бассейна и двух ведер. Например: нужно получить 4 литра при помощи двух ведер емкостью 3 и 5 литров. Имеется ее решение методом бильярдного шара .

Необходимо создать генератор, выдающий пары чисел - наполненности сосудов. Пример работы:

Buckets = pool(3,5) for a,b in buckets: print("a=",a," b=",b) if b==4: break



Есть вопросы?

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: