Python:打印一个生成器expression式?

在Python shell中,如果我input列表理解,如:

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

如果我input一个生成器expression式,我不会得到如此友好的回应:

 >>> (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, acgimnopsu BM 

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

快速回答:

做一个生成器expression式的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")] 

是的,这会将生成器expression式转换为列表理解。 这是一样的事情和调用列表()。 因此,将生成器expression式放入列表的方法是将括号括起来。

详细说明:

生成器expression式是expression式的“裸体”。 像这样:

 x*x for x in range(10) 

现在,你不能把它粘在一行上,你会得到一个语法错误。 但是你可以把括号括起来。

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

这有时被称为生成器理解,虽然我认为官方名称仍然是生成器expression式,没有任何区别,括号只是在那里使语法有效。 如果您将它作为函数的唯一parameter passing,则不需要它们,例如:

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

基本上Python 3和Python 2.7中可用的所有其他解释都只是生成器expression式的语法糖。 设置理解:

 >>> {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下,列表parsing不仅仅是语法糖。 但唯一的区别是,Python将在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中获得生成器expression式内容的最佳方式是让列表理解出来! 但是,如果你已经有一个生成器对象,这显然不起作用。 这样做只会列出一个生成器:

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

您可以将expression式包装到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'] 

与列表或字典不同,生成器可以是无限的。 这样做不起作用:

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

或者你可以总是map一个迭代器,而不需要build立一个中间列表:

 >>> _ = map(sys.stdout.write, (x for x in string.letters if x in (y for y in "BigMan on campus"))) acgimnopsuBM 
 >>> 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']