Подтвердить что ты не робот

Python: напечатать выражение генератора?

В оболочке Python, если я ввел понимание списка, например:

>>> [x for x in string.letters if x in [y for y in "BigMan on campus"]]

Я получаю красиво напечатанный результат:

['a', 'c', 'g', 'i', 'm', 'n', 'o', 'p', 's', 'u', 'B', 'M']

То же самое для понимания словаря:

>>> {x:x*2 for x in range(1,10)}
{1: 2, 2: 4, 3: 6, 4: 8, 5: 10, 6: 12, 7: 14, 8: 16, 9: 18}

Если я ввожу выражение генератора, я получаю не такой дружеский ответ:

>>> (x for x in string.letters if x in (y for y in "BigMan on campus"))
<generator object <genexpr> at 0x1004a0be0>

Я знаю, что могу это сделать:

>>> for i in _: print i,
a c g i m n o p s u B M

Помимо этого (или написания вспомогательной функции) я могу легко оценить и распечатать этот объект-генератор в интерактивной оболочке?

4b9b3361

Ответ 1

Быстрый ответ:

Выполнение list() вокруг выражения генератора (почти) в точности эквивалентно наличию [] скобок вокруг него. Так что да, вы можете сделать

>>> list((x for x in string.letters if x in (y for y in "BigMan on campus")))

Но вы также можете сделать

>>> [x for x in string.letters if x in (y for y in "BigMan on campus")]

Да, это превратит выражение генератора в понимание списка. Это то же самое и вызывающий список() на нем. Таким образом, способ сделать выражение генератора в список состоит в том, чтобы поместить вокруг него скобки.

Подробное объяснение:

Выражение генератора является выражением "голый" for. Например:

x*x for x in range(10)

Теперь вы не можете вставить это в строку самостоятельно, вы получите синтаксическую ошибку. Но вы можете помещать вокруг нее круглые скобки.

>>> (x*x for x in range(10))
<generator object <genexpr> at 0xb7485464>

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

>>> sorted(x*x for x in range(10))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

В принципе, все другие возможности, доступные в Python 3 и Python 2.7, - это просто синтаксический сахар вокруг выражения генератора. Установить понимание:

>>> {x*x for x in range(10)}
{0, 1, 4, 81, 64, 9, 16, 49, 25, 36}

>>> set(x*x for x in range(10))
{0, 1, 4, 81, 64, 9, 16, 49, 25, 36}

Понимания Дикта:

>>> dict((x, x*x) for x in range(10))
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

>>> {x: x*x for x in range(10)}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

И перечислить понимание в Python 3:

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

>>> [x*x for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

В Python 2, понимание списков - это не просто синтаксический сахар. Но единственное различие заключается в том, что x будет находиться под утечкой Python 2 в пространство имен.

>>> x
9

Пока под Python 3 вы получите

>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

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

>>> foo = (x*x for x in range(10))
>>> [foo]
[<generator object <genexpr> at 0xb7559504>]

В этом случае вам нужно будет позвонить list():

>>> list(foo)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Хотя это работает, но выглядит глупо:

>>> [x for x in foo]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Ответ 2

Вы можете просто обернуть выражение при вызове list:

>>> list(x for x in string.letters if x in (y for y in "BigMan on campus"))
['a', 'c', 'g', 'i', 'm', 'n', 'o', 'p', 's', 'u', 'B', 'M']

Ответ 3

В отличие от списка или словаря, генератор может быть бесконечным. Это не сработает:

def gen():
    x = 0
    while True:
        yield x
        x += 1
g1 = gen()
list(g1)   # never ends

Кроме того, чтение генератора меняет его, поэтому нет идеального способа его просмотра. Чтобы увидеть образец выходного сигнала генератора, вы можете сделать

g1 = gen()
[g1.next() for i in range(10)]

Ответ 4

Или вы всегда можете map над итератором, без необходимости создания промежуточного списка:

>>> _ = map(sys.stdout.write, (x for x in string.letters if x in (y for y in "BigMan on campus")))
acgimnopsuBM

Ответ 5

>>> list(x for x in string.letters if x in (y for y in "BigMan on campus"))
['a', 'c', 'g', 'i', 'm', 'n', 'o', 'p', 's', 'u', 'B', 'M']