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


Сегодня я расскажу о таком типе данных, как списки , операциях над ними и методах, о генераторах списков и о применении списков.

Что такое списки?

Списки в Python - упорядоченные изменяемые коллекции объектов произвольных типов (почти как массив, но типы могут отличаться).

Чтобы использовать списки, их нужно создать. Создать список можно несколькими способами. Например, можно обработать любой итерируемый объект (например, ) встроенной функцией list :

>>> list ("список" ) ["с", "п", "и", "с", "о", "к"]

Список можно создать и при помощи литерала:

>>> s = # Пустой список >>> l = [ "s" , "p" , [ "isok" ], 2 ] >>> s >>> l ["s", "p", ["isok"], 2]

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

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

>>> c = [ c * 3 for c in "list" ] >>> c ["lll", "iii", "sss", "ttt"]

Возможна и более сложная конструкция генератора списков:

>>> c = [ c * 3 for c in "list" if c != "i" ] >>> c ["lll", "sss", "ttt"] >>> c = [ c + d for c in "list" if c != "i" for d in "spam" if d != "a" ] >>> c ["ls", "lp", "lm", "ss", "sp", "sm", "ts", "tp", "tm"]

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

Функции и методы списков

Создать создали, теперь нужно со списком что-то делать. Для списков доступны основные , а также методы списков.

Таблица "методы списков"

Метод Что делает
list.append (x) Добавляет элемент в конец списка
list.extend (L) Расширяет список list, добавляя в конец все элементы списка L
list.insert (i, x) Вставляет на i-ый элемент значение x
list.remove (x) Удаляет первый элемент в списке, имеющий значение x. ValueError, если такого элемента не существует
list.pop ([i]) Удаляет i-ый элемент и возвращает его. Если индекс не указан, удаляется последний элемент
list.index (x, ]) Возвращает положение первого элемента со значением x (при этом поиск ведется от start до end)
list.count (x) Возвращает количество элементов со значением x
list.sort () Сортирует список на основе функции
list.reverse () Разворачивает список
list.copy () Поверхностная копия списка
list.clear () Очищает список

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

>>> l = [ 1 , 2 , 3 , 5 , 7 ] >>> l . sort () >>> l >>> l = l . sort () >>> print (l ) None

И, напоследок, примеры работы со списками:

>>> a = [ 66.25 , 333 , 333 , 1 , 1234.5 ] >>> print (a . count (333 ), a . count (66.25 ), a . count ("x" )) 2 1 0 >>> a . insert (2 , - 1 ) >>> a . append (333 ) >>> a >>> a . index (333 ) 1 >>> a . remove (333 ) >>> a >>> a . reverse () >>> a >>> a . sort () >>> a [-1, 1, 66.25, 333, 333, 1234.5]

Изредка, для увеличения производительности, списки заменяют гораздо менее гибкими

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() с подходящей функцией. Конечно, вы можете комбинировать их с герератором списков.

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

В Python просто генераторы и генераторы списков - разные вещи. Здесь есть проблема перевода с английского. То, что мы привыкли называть генератором списка, в английском варианте звучит как "list comprehension " и к генераторам никакого отношения не имеет.

Слово "comprehension" (понимание, осмысление) оказывается как бы не в тему при переводе на русский. Получается что-то вроде "понимание списка". Поэтому мы говорим "генератор списка", понимая под словом "генератор" не объект, а синтаксическую конструкцию, которая генерирует, то есть создает, список.

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

Быстрым способом создания относительно простых объектов-генераторов являются генераторные выражения - generator expressions . Синтаксис этих выражений похож на синтаксис генераторов списков. Однако они возвращают разные типы объектов. Первый - объект-генератор. Второй - список.

Сначала рассмотрим генераторы списков, чтобы привыкнуть к синтаксической конструкции.

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

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

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

>>> a = [ 1 , 2 , 3 ] >>> b = [ i+10 for i in a] >>> a [ 1 , 2 , 3 ] >>> b [ 11 , 12 , 13 ]

В примере выше генератором списка является выражение . Здесь a - итерируемый объект. В данном случае это другой список. Из него извлекается каждый элемент в цикле for. Перед for описывается действие, которое выполняется над элементом перед его добавлением в новый список.

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

>>> a = [ 1 , 2 , 3 ] >>> a = [ i+10 for i in a] >>> a [ 11 , 12 , 13 ]

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

>>> for index, value in enumerate (a) : ... a [ index] = value + 10 ... >>> a [ 11 , 12 , 13 ]

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

>>> ls0 = [ 1 , 2 , 3 ] >>> ls1 = ls0 >>> ls1.append (4 ) >>> ls0 [ 1 , 2 , 3 , 4 ] >>> ls1 = [ i+1 for i in ls1] >>> ls1 [ 2 , 3 , 4 , 5 ] >>> ls0 [ 1 , 2 , 3 , 4 ]

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

Перебираемым в цикле for объектом может быть быть не только список. В примере ниже в список помещаются строки файла.

>>> lines = [ line.strip () for line in open ("text.txt" ) ] >>> lines [ "one" , "two" , "three" ]

В генератор списка можно добавить условие:

>>> from random import randint >>> nums = [ randint(10 , 20 ) for i in range (10 ) ] >>> nums [ 18 , 17 , 11 , 11 , 15 , 18 , 11 , 20 , 10 , 19 ] >>> nums = [ i for i in nums if i%2 == 0 ] >>> nums [ 18 , 18 , 20 , 10 ]

Генераторы списков могут содержать вложенные циклы:

>>> a = "12" >>> b = "3" >>> c = "456" >>> comb = [ i+j+k for i in a for j in b for k in c] >>> comb [ "134" , "135" , "136" , "234" , "235" , "236" ]

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

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

>>> a = { i:i**2 for i in range (11 , 15 ) } >>> a { 11 : 121 , 12 : 144 , 13 : 169 , 14 : 196 }

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

>>> a = { i for i in range (11 , 15 ) } >>> a set ([ 11 , 12 , 13 , 14 ] ) >>> b = { 1 , 2 , 3 } >>> b set ([ 1 , 2 , 3 ] )

Генераторы

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

>>> a = (i for i in range (2 , 8 ) ) >>> a < generator object < genexpr> at 0x7efc88787910 > >>> for i in a: ... print (i) ... 2 3 4 5 6 7

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

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

Выражение, создающее генератор, это сокращенная запись следующего:

>>> def func(start, finish) : ... while start < finish: ... yield start * 0.33 ... start += 1 ... >>> a = func(1 , 4 ) >>> a < generator object func at 0x7efc88787a50 > >>> for i in a: ... print (i) ... 0.33 0.66 0.99

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

>>> b = (i*0.33 for i in range (1 , 4 ) ) >>> b < generator object < genexpr> at 0x7efc88787960 > >>> for i in b: ... print (i) ... 0.33 0.66 0.99

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

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

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







2024 © gtavrl.ru.