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

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

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

>>> a = []
>>> for i in range(1,15):
...     a.append(i)
...
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

На создание списка ушло три строчки кода. Генератор же сделает это за одну:

>>> a = [i for i in range(1,15)]
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

Здесь конструкция [i for i in range(1,15)] является генератором списка. Вся конструкция заключается в квадратные скобки, что как бы говорит, что будет создан список. Внутри квадратных скобок можно выделить три части: 1) что делаем с элементом (в данном случае ничего не делаем, просто добавляем в список), 2) что берем (в данном случае элемент i), 3) откуда берем (здесь из объекта range). Части отделены друг от друга ключевыми словами for и in.

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

>>> a = [2,-2,4,-4,7,5]
>>> b = [i**2 for i in a]
>>> b
[4, 4, 16, 16, 49, 25]

В данном случае в генераторе списка берется каждый элемент из списка a и возводится в квадрат. Таким образом, 1) что делаем - возводим элемент в квадрат, 2) что берем - элемент, 3) откуда берем - из списка a.

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

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

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

В этом примере генерируемый список b состоит из вложенных списков. Если бы в генераторе были опущены квадратные скобки в выражении [i,a[i]], то произошла бы ошибка. Если все же надо получить одноуровневый список из ключей и значений словаря, надо взять каждый вложенный список и из него взять каждый элемент. Это достигается за счет вложенной конструкции for, что демонстрируется в строчке c = [j for i in b for j in i]. "Классический" синтаксис для заполнения списка c выглядел бы так:

>>> c = []
>>> for i in b:
...     for j in i:
...          c.append(j)
...
>>> c
[1, 10, 2, 20, 3, 30]

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

>>> a = "lsj94ksd231 9"
>>> b = [int(i) for i in a if '0'<=i<='9']
>>> b
[9, 4, 2, 3, 1, 9]

Или заполнить список числами, кратными 30 или 31:

>>> a = [i for i in range(30,250)
... if i%30 == 0 or i%31 == 0]
>>> a
[30, 31, 60, 62, 90, 93, 120, 124, 150,
155, 180, 186, 210, 217, 240, 248]

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