Сообщить об ошибке.

Сокращенная запись генератора в Python

Выражение-генератор - это выражение, которое возвращает итератор, которые более удобны для памяти (потребляют меньше памяти).

Некоторые простые генераторы могут быть лаконично закодированы в виде выражений с использованием синтаксиса, аналогичного списка-выражения, но с круглыми скобками вместо квадратных скобок. Эти выражения предназначены для ситуаций, когда генератор сразу же используется функцией.

>>> (i*i for i in range(5))
# <generator object <genexpr> at 0x7f2ee9b47d10>

Выражения генераторы более компактны, но менее универсальны, чем полные генераторные определения и, как правило, более удобны для памяти, чем эквивалентные списки. Обратите внимание, если обрабатывается большая структура данных без использования генератора, то она сразу вся загружается в память, что займет значительную часть памяти, а в некоторых случаях оперативной памяти может не хватить и тогда приложение будет вызывать исключение MemoryError. В случае использования выражения-генератора, такого не происходит, так как элементы создаются и будут обрабатываться по-одному.

Ограничения выражений-генераторов.

  • Выражения-генераторы нельзя писать без скобок - это синтаксическая ошибка;

    >>> i*i for i in range(10)
    # File "<stdin>", line 1
    #     i*i for i in range(10)
    #         ^
    # SyntaxError: invalid syntax
    
  • При передаче в функцию дополнительные скобки необязательны;

    # сумма квадратов
    >>> sum(i*i for i in range(10))
    # 285
    
  • Выражения-генераторы не поддерживают получение длины функцией len();

    >>> len(i*i for i in range(10))
    # Traceback (most recent call last):
    # File "<stdin>", line 1, in <module>
    # TypeError: object of type 'generator' has no len()
    
  • Выражения-генераторы не поддерживают получение элемента по индексу;

    >>> gen = (i*i for i in range(10))
    >>> gen[1]
    # Traceback (most recent call last):
    # File "<stdin>", line 1, in <module>
    # TypeError: 'generator' object is not subscriptable
    
  • К выражению-генератору нельзя применить обычные операции среза или функцию slice(). Для этих целей, можно воспользоваться функцией itertools.islice() модуля itertools.

    >>> gen = (i*i for i in range(10))
    >>> gen[1:5]
    # Traceback (most recent call last):
    # File "<stdin>", line 1, in <module>
    # TypeError: 'generator' object is not subscriptable
    >>> import itertools
    >>> list(itertools.islice(gen, 1, 5))
    # [1, 4, 9, 16]
    
  • После использования/итерации по выражению-генератору, оно остается пустым;

    >>> gen = (i*i for i in range(10))
    >>> list(gen)   
    # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    >>> list(gen)   
    # []
    

Примеры использования выражения-генератора:

>>> xvec = [10, 20, 30]
>>> yvec = [7, 5, 3]
#скалярное произведение
>>> sum(x*y for x,y in zip(xvec, yvec))
# 260

# Согласно PEP8 - то что в скобках, то можно переносить
# следовательно выражение-генератор можно записать
# так, что бы было удобно его читать
>>> unique_words = set(
                      word 
                      for line in page
                      for word in line.split()
                      )

# и еще пример
>>> valedictorian = max(
                        (student.gpa, student.name) 
                        for student in graduates
                        )

# перевернем слово
>>> data = 'golf'
>>> drow = (
...         data[i] 
...         for i in range(len(data) - 1, -1, -1)
...         )
>>> list(drow)
# ['f', 'l', 'o', 'g']