如何打印生成器表达式?

在 Python shell 中,如果输入以下列表内涵:

>>> [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

除此之外(或者编写一个辅助函数) ,我是否可以轻松地在交互式 shell 中计算和打印生成器对象?

201565 次浏览

你可以直接把这个表达式包装在对 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']
>>> 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']

快速回答:

在一个生成器表达式周围执行 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")]

是的那会把生成器表达式变成一个列表内涵。这是相同的事情和调用 list ()在它上面。因此,将生成器表达式转换为列表的方法是在其周围加上括号。

详细解释:

生成器表达式是一个“裸”的 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]

在 Python2中,列表理解不仅仅是语法上的“糖”。但唯一的区别是,Python 2下的 x 将泄漏到名称空间中。

>>> 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]

或者,您总是可以通过迭代器执行 map,而不需要构建中间列表:

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

与列表或字典不同,生成器可以是无限的:

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)]

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

例如。

list(genexpr)
dict(genexpr)
set(genexpr)
for data in genexpr:

附加条款

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

data=[x for x in range(0,10)]

而不是吸毒

genexpr=(x for x in range(0,10))
data=list(genexpr)
print(i for i in range(9))

如果我们运行这个命令,我们将得到如下输出:-< Generator object at 0x000001F01A153E40 >

打印生成器的一种简单方法是将其转换为列表。 因此,如果我们将代码修改为 print(*[i for i in range(9)])

所以我们得到的输出是: 012345678

你也可以这样做:

gen = (i for i in 'abcde')
print( *gen ) # => a b c d e