…·········print(row, col)
…
1 1
1 2
2 1
2 2
3 1
3 2
Теперь воспользуемся включением и присвоим его переменной cells, создавая тем самым список кортежей (row, col):
>>> rows = range(1,4)
>>> cols = range(1,3)
>>> cells = [(row, col) for row in rows for col in cols]
>>> for cell in cells:
…·····print(cell)
…
(1, 1)
(1, 2)
(2, 1)
(2, 2)
(3, 1)
(3, 2)
Кстати, вы можете воспользоваться распаковкой кортежа, чтобы выдернуть значения row и col из каждого кортежа по мере итерирования по списку cells:
>>> for row, col in cells:
…·····print(row, col)
…
1 1
1 2
2 1
2 2
3 1
3 2
Фрагменты for row… и for col… во включении также могут иметь свои проверки if.
Включение словаря
Для словарей также можно создать включение. Простейшая его форма выглядит привычно:
{ выражение_ключа: выражение_значения for выражение in итерабельный объект }
Как и в случае с включениями списка, выделения словарей также имеют проверки if и несколько операторов for:
>>> word = 'letters'
>>> letter_counts = {letter: word.count(letter) for letter in word}
>>> letter_counts
{'l': 1, 'e': 2, 't': 2, 'r': 1, 's': 1}
Мы запускаем цикл, проходя по каждой из семи букв в строке letters, и считаем, сколько раз появляется эта буква. Два наших вызова word.count(letter) — это лишь пустая трата времени, поскольку нам нужно подсчитать буквы «e» и «t» два раза. Но когда мы считаем буквы «e» во второй раз, то не причиняем вреда, поскольку лишь заменяем уже существующую запись в словаре; то же относится и к подсчету букв «t». Следующий способ решения задачи более характерен для Python:
>>> word = 'letters'
>>> letter_counts = {letter: word.count(letter) for letter in set(word)}
>>> letter_counts
{'t': 2, 'l': 1, 'e': 2, 'r': 1, 's': 1}
Ключи словаря располагаются в ином, чем в предыдущем примере, порядке, поскольку итерирование по результату работы функции set(word) возвращает буквы в другом порядке, нежели итерирование по строке word.
Включение множества
Никто не хочет оказаться обиженным, поэтому даже у множеств есть включения. Простейшая версия выглядит как включение списка или словаря, которые вы только что видели:
{ выражение for выражение in итерабельный объект}
Более длинные версии (проверки if, множественные операторы for) также доступны для множеств:
>>> a_set = {number for number in range(1,6) if number % 3 == 1}
>>> a_set
{1, 4}
Включение генератора
Для кортежей не существует включений. Вы могли подумать, что замена квадратных скобок у выделения списка на круглые создаст включение кортежа. Может даже показаться, что это работает, поскольку исключение не будет сгенерировано, если вы напишете следующее:
>>> number_thing = (number for number in range(1, 6))
В круглые скобки заключено включение генератора, оно возвращает объект генератора:
>>> type(number_thing)
<class 'generator'>
Сами генераторы мы рассмотрим более детально позже в данной главе. Применение генераторов — это один из способов предоставить данные итератору.
Вы можете итерировать непосредственно по этому объекту генератора, как показано здесь:
>>> for number in number_thing:
…·····print(number)
…
1
2
3
4
5
Или же вы можете обернуть вызов list() вокруг включения генератора, чтобы заставить его работать как включение списка:
>>> number_list = list(number_thing)
>>> number_list
[1, 2, 3, 4, 5]
Генератор может быть запущен лишь однажды. Списки, множества и словари существуют в памяти, но генератор создает свои значения во время работы программы и выдает их по одному за раз через итератор. Он не запоминает их, поэтому вы не можете перезапустить или создать резервную копию генератора.
Если вы попробуете проитерировать по генератору заново, то обнаружите, что он истощен:
>>> try_again = list(number_thing)
>>> try_again
[]
Вы можете создать генератор из включения генератора, как мы сделали это здесь, или из функции генератора. Сначала мы поговорим о функциях в целом, а затем рассмотрим частный случай — функции генератора.