Генератор списка питон. Списки (list)

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

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

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

Python поддерживает концепцию, называемую "list comprehensions" (генераторы списков ).

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

Ниже обычные способы описание списков (или коллекций, или кортежей, или векторов) в математике:

S = {x 2: x in {0 ... 9}}
V = {1,2,4,8, ..., 2 2 }
M = {x | x in S and x even}

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

Как наши выражения выглядят в Python-е:

>>> S = >>> V = >>> M = >>> >>> print S; print V; print M
Уверен, что вы хотите видеть более сложный пример. :) Ниже будет представлен еще один способ нахождения простых чисел . Интересным является то, что мы сперва строим список из не простых чисел, используя первый генератор списков, а затем второй генератор списков чтобы получить "инверсию" списка, которая является простыми числами.

>>> noprimes = >>> primes = >>> print primes NB: Вы можете встраивать генераторы списков один в другой, так что могли бы в нашем примере обойтись одним единственным выражением (без необходимости использовать переменную "noprimes" для хранения промежуточных результатов). Однако, наше выражение получилось бы длинным и менее читаемым, что не рекомендуется. Конечно, генератор списков может использоваться не только для чисел. Списки могут содержать элементы любого типа, включая строки, встроенные списки и функции. Вы даже можете смешивать различные типы в одном списке.

В следующем примере мы имеем дело со списком строк и генерим список списков. Каждый из встроенных списков содержит две строки и одно целочисленное значение.

>>> words = "The quick brown fox jumps over the lazy dog".split() >>> print words ["The", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog"] >>> stuff = [ for w in words] >>> for i in stuff: ... print i
["THE", "the", 3] ["QUICK", "quick", 5] ["BROWN", "brown", 5] ["FOX", "fox", 3] ["JUMPS", "jumps", 5] ["OVER", "over", 4] ["THE", "the", 3] ["LAZY", "lazy", 4] ["DOG", "dog", 3] >>> stuff = map(lambda w: , words) >>> for i in stuff: ... print i ["THE", "the", 3] ["QUICK", "quick", 5] ["BROWN", "brown", 5] ["FOX", "fox", 3] ["JUMPS", "jumps", 5] ["OVER", "over", 4] ["THE", "the", 3] ["LAZY", "lazy", 4] ["DOG", "dog", 3]
В примере выше демонстрируется, что вы реализовывать нашу задачу двумя способами - сперва используя генератор списков, а затем используя map() и lambda функцию. Однако есть случаи, когда вы не можете использовать map() и должны применять генаротор списков, и наоборот. Если применимы два способа, то зачастую лучше пользоваться генератором списков, потому что он более эффективный и более читаемый, в большинстве случаев.

Вы не можете использовать генераторы списков, когда условие составления является слишком сложным, чтобы быть выраженным оперраторами "for" и "if" или же когда условие меняется динамически во время работы программы. В этом случае лучше использовать map() и/или filter() с подходящей функцией. Конечно, вы можете комбинировать их с герератором списков.

Оригинальная статья:

| |

Генераторы списков (list comprehensions) позволяют быстро создать список на основе существующих списков. При помощи генератора можно построить список на основе любого итерируемого типа данных (к примеру, из строк или кортежей).

В результате цикл создаст такой же список:

["8", "h", "o", "s", "t"]

Условные выражения в генераторах списков

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

Давайте рассмотрим генератор с выражением if:

fish_tuple = ("blowfish", "clownfish", "catfish", "octopus")
fish_list =
print(fish_list)

Список использует кортеж fish_tuple в качестве основы для нового списка fish_list.

Ключевые слова for и in используются так же, как в предыдущем размере. Кроме того, генератор содержит выражение if, благодаря чему он исключает из списка строку ‘octopus’.

Запросите содержимое списка fish_list и убедитесь, что он содержит все элементы fish_tuple, кроме ‘octopus’.

["blowfish", "clownfish", "catfish"]

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

Теперь рассмотрим другой пример, в котором используются математические операции, цифры и метод range().


print(number_list)

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

Новый список number_list будет содержать квадратичные значения каждого чётного элемента в диапазоне от 0-9. В результате получится такой список:

Давайте разберём этот пример пошагово. Если вместо x ** 2 for x использовать просто x for x, список будет выглядеть так:

number_list =
print(number_list)

После этого в генератор было добавлено условное выражение:

number_list =
print(number_list)

Выражение if исключило из списка все нечётные числа.

Теперь осталось добавить оператор, который возведёт все элементы в квадрат:

number_list =
print(number_list)

Теперь каждый элемент списка будет возведён в квадрат.

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

number_list =
print(number_list)

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

Итераторы в языке Python

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

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

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

> > > num_list = > > > for i in num_list: print (i) 1 2 3 4 5

Как уже было сказано, объекты, элементы которых можно перебирать в цикле for , содержат в себе объект итератор, для того, чтобы его получить необходимо использовать функцию iter() , а для извлечения следующего элемента из итератора – функцию next() .

> > > itr = iter (num_list) > > > print (next(itr)) 1 > > > print (next(itr)) 2 > > > print (next(itr)) 3 > > > print (next(itr)) 4 > > > print (next(itr)) 5 > > > print (next(itr)) Traceback (most recent call last): File "" , line 1 , in < module> print (next(itr)) StopIteration

Как видно из приведенного выше примера вызов функции next(itr) каждый раз возвращает следующий элемент из списка, а когда эти элементы заканчиваются, генерируется исключение StopIteration .

Создание собственных итераторов

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

__init__ < self .limit: self .counter += 1 return 1 else : raise StopIteration s_iter1 = SimpleIterator(3 ) print (next(s_iter1)) print (next(s_iter1)) print (next(s_iter1)) print (next(s_iter1))

В нашем примере при четвертом вызове функции next() будет выброшено исключение StopIteration . Если мы хотим, чтобы с данным объектом можно было работать в цикле for , то в класс SimpleIterator нужно добавить метод __iter__() , который возвращает итератор, в данном случае этот метод должен возвращать self .

class SimpleIterator : def __iter__ (self ): return self def __init__ (self , limit ): self .limit = limit self .counter = 0 def __next__ (self ): if self .counter < self .limit: self .counter += 1 return 1 else : raise StopIteration s_iter2 = SimpleIterator(5 ) for i in s_iter2: print (i)

Генераторы

Генераторы позволяют значительно упростить работу по конструированию итераторов. В предыдущих примерах, для построения итератора и работы с ним, мы создавали отдельный класс. Генератор – это функция, которая будучи вызванной в функции next() возвращает следующий объект согласно алгоритму ее работы. Вместо ключевого слова return в генераторе используется yield . Проще всего работу генератор посмотреть на примере. Напишем функцию, которая генерирует необходимое нам количество единиц.

def simple_generator (val ): while val > 0 : val -= 1 yield 1 gen_iter = simple_generator(5 ) print (next(gen_iter)) print (next(gen_iter)) print (next(gen_iter)) print (next(gen_iter)) print (next(gen_iter)) print (next(gen_iter))

Данная функция будет работать точно также, как класс SimpleIterator из предыдущего примера.

Ключевым моментом для понимания работы генераторов является то, при вызове yield функция не прекращает свою работу, а “замораживается” до очередной итерации, запускаемой функцией next() . Если вы в своем генераторе, где-то используете ключевое слово

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

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 !