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