Курс: Python

Лекция: Генераторы списков

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

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

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

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

res = [x for x in xrange(1, 25, 2)]
...
print res

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

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

res = [x**2 for x in xrange(1, 25, 2) if x % 3 != 0]
...
print res

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

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

Генераторы

Конструкции типа mylist = [x*x for x in range(3)] формируют списки элементов, значения которых хранятся в памяти. К ним можно применять конструкцию 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[1:3]. Но, генераторы позволяют сократить объем памяти для запуска программы.

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