Перейти до змісту

Генератори-вирази

Деякі прості генератори можна записати у вигляді виразів. Такі вирази виглядають так:

  1. Вираз з деякими змінними.
  2. Одне чи декілька ключових слів for. Задається які значення будуть приймати вищезгадані змінні. Синтаксис відповідає заголовку цикла for.
  3. Нуль або більше умов, які фільтрують значення змінних. Синтаксис відповідає заголовку оператора 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']
>>>
Back to top