Python:打印一个生成器表达式?

the*_*olf 93 python

在Python shell中,如果我输入列表解析,例如:

>>> [x for x in string.letters if x in [y for y in "BigMan on campus"]]
Run Code Online (Sandbox Code Playgroud)

我得到了一个很好的印刷结果:

['a', 'c', 'g', 'i', 'm', 'n', 'o', 'p', 's', 'u', 'B', 'M']
Run Code Online (Sandbox Code Playgroud)

字典理解相同:

>>> {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}
Run Code Online (Sandbox Code Playgroud)

如果我输入一个生成器表达式,我得不到这么友好的响应:

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

我知道我可以这样做:

>>> for i in _: print i,
a c g i m n o p s u B M
Run Code Online (Sandbox Code Playgroud)

除此之外(或编写辅助函数)我可以在交互式shell中轻松评估和打印该生成器对象吗?

Len*_*bro 145

快速回答:

list()围绕发电机表达是(几乎)完全等同于具有 []在其周围括号.所以是的,你可以做到

>>> list((x for x in string.letters if x in (y for y in "BigMan on campus")))
Run Code Online (Sandbox Code Playgroud)

但你也可以这样做

>>> [x for x in string.letters if x in (y for y in "BigMan on campus")]
Run Code Online (Sandbox Code Playgroud)

是的,这会将生成器表达式转换为列表理解.它是相同的东西,并在其上调用list().因此,将生成器表达式放入列表的方法是在其周围放置括号.

详细说明:

生成器表达式是"裸" for表达式.像这样:

x*x for x in range(10)
Run Code Online (Sandbox Code Playgroud)

现在,你不能将它自己粘在一条线上,你会得到一个语法错误.但你可以在它周围加上括号.

>>> (x*x for x in range(10))
<generator object <genexpr> at 0xb7485464>
Run Code Online (Sandbox Code Playgroud)

这有时被称为生成器理解,虽然我认为官方名称仍然是生成器表达式,但实际上没有任何区别,括号仅用于使语法有效.如果您将其作为函数的唯一参数传递给函数,则不需要它们,例如:

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

基本上,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}
Run Code Online (Sandbox Code Playgroud)

Dict理解:

>>> 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}
Run Code Online (Sandbox Code Playgroud)

并在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]
Run Code Online (Sandbox Code Playgroud)

在Python 2下,列表推导不仅仅是语法糖.但唯一的区别是x将在Python 2下泄漏到命名空间中.

>>> x
9
Run Code Online (Sandbox Code Playgroud)

在Python 3下你会得到

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

这意味着在Python中获得生成器表达式内容的良好打印输出的最佳方法是从中获取列表理解!但是,如果您已经有一个生成器对象,这显然不起作用.这样做只会列出一个生成器:

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

在这种情况下,您需要致电list():

>>> list(foo)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Run Code Online (Sandbox Code Playgroud)

虽然这有效,但有点愚蠢:

>>> [x for x in foo]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Run Code Online (Sandbox Code Playgroud)

  • 官方术语仍然是"生成器表达",因为"理解"一词意味着迭代,这是genexp*不做*的一件事,因为这个问题和答案很好地说明:) (5认同)
  • `list( generator-expression )` 不打印生成器表达式;它正在生成一个列表(然后在交互式 shell 中打印它)。在 Python 3 中,您可以将生成器表达式放入打印语句中,而不是生成列表。即)`print(*(generator-expression))`。这将在开头和结尾打印没有逗号和括号的元素。 (3认同)

Bjö*_*lex 16

您可以在调用中将表达式包装为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']
Run Code Online (Sandbox Code Playgroud)


cha*_*had 15

与列表或字典不同,生成器可以是无限的.这样做是行不通的:

def gen():
    x = 0
    while True:
        yield x
        x += 1
g1 = gen()
list(g1)   # never ends
Run Code Online (Sandbox Code Playgroud)

此外,读取生成器会改变它,因此没有一种完美的方式来查看它.要查看生成器输出的样本,您可以这样做

g1 = gen()
[g1.next() for i in range(10)]
Run Code Online (Sandbox Code Playgroud)

  • 投票是因为生成器可以是无限的,因此会导致循环或完全停止(取决于您的规格(笑))。 (2认同)
  • 在 Python 3 中使用“[next(g1) for i in range(10)]”。 (2认同)

lbo*_*lla 12

或者您可以始终map在迭代器上,而无需构建中间列表:

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

  • 这是实际打印生成器内容而不创建巨大对象的唯一答案。 (3认同)

小智 5

生成器对象不存储实际数据,它基本上只是一个表达式。程序无法在不求值的情况下打印表达式的值。生成器对象(生成器表达式)可以通过类型转换为任何可迭代数据类型来求值。

例如。

list(genexpr)
dict(genexpr)
set(genexpr)
for data in genexpr: 
Run Code Online (Sandbox Code Playgroud)

额外的

生成生成器表达式然后进行类型转换比直接创建所需的数据类型对象慢 20%。因此,如果我们需要完整数据,最好使用

data=[x for x in range(0,10)]
Run Code Online (Sandbox Code Playgroud)

比使用

genexpr=(x for x in range(0,10))
data=list(genexpr)
Run Code Online (Sandbox Code Playgroud)