Генератори-вирази
Деякі прості генератори можна записати у вигляді виразів. Такі вирази виглядають так:
- Вираз з деякими змінними.
- Одне чи декілька ключових слів
for
. Задається які значення будуть приймати вищезгадані змінні. Синтаксис відповідає заголовку циклаfor
. - Нуль або більше умов, які фільтрують значення змінних. Синтаксис відповідає заголовку оператора
if
.
Такі вирази називають виразами-генераторами (generator expressions).
Приклад. Необхідно отримати послідовність парних ступеней числа 2 від 0 до 10 включно. Напишемо спочатку "звичайний" генератор:
>>> def pow2_gen():
... for x in range(11):
... if x % 2 == 0:
... yield 2 ** x
...
>>>
Спробуємо знайти суму цих чисел. Функція sum()
приймає ітерабельний об'єкт (переконайтесь у цьому самостійно), отже ми сміливо можемо передати їй генератор:
>>> print(sum(pow2_gen()))
1365
>>>
А тепер напишемо генератор-вираз:
>>> g = (2**x for x in range(11) if x%2==0)
>>> g
<generator object <genexpr> at 0x0000029D8FF1FFC0>
>>> sum(g)
1365
>>>
Зауважте: вираз для генератора ми включили у круглі дужки. Якщо цього не зробити, виникає неоднозначність і Python не може точно інтрерпретувати такий вираз.
Шахівниця
Спробуємо за допомогою генератор-вираза отримати усі клітинки шахівниці білого кольору:
>>> columns = 'ABCDEFGH'
>>> rows = '12345678'
>>> white_fields_generator = (
... column + row
... for column in columns
... for row in rows
... if (columns.index(column)+rows.index(row)) % 2 == 1
... )
>>>
Давайте отримаємо усі білі клітинки одним символьним рядком:
>>> print(' '.join(white_fields_generator))
A2 A4 A6 A8 B1 B3 B5 B7 C2 C4 C6 C8 D1 D3 D5 D7 E2 E4 E6 E8 F1 F3 F5 F7 G2 G4 G6 G8 H1 H3 H5 H7
>>>
Метод str.join()
приймає ітерабельний об'єкт (переконайтесь у цьому самостійно), а генератор і є ітерабельним об'єктом.
А давайте отримаємо усі білі клітинки перших двох рядів шахівниці. Будемо використовувати генератор як звичайний ітератор самим "примітивним" способом — використовуючи функцію next()
:
>>> white_fields_generator = (column + row for column in columns for row in rows if (columns.index(column)+rows.index(row)) % 2 == 1)
>>> for _ in range(8):
... print(next(white_fields_generator))
...
A2
A4
A6
A8
B1
B3
B5
B7
>>>
Зауважте: перед використанням генератор треба створити знову.
Можна і по-іншому, подумайте який спосіб краще:
>>> white_fields_generator = (column + row for column in columns for row in rows if (columns.index(column)+rows.index(row)) % 2 == 1)
>>> print(list(white_fields_generator)[:8])
['A2', 'A4', 'A6', 'A8', 'B1', 'B3', 'B5', 'B7']
>>>