在Python中没有列出理解

join清单:

>>> ''.join([ str(_) for _ in xrange(10) ]) '0123456789' 

join必须采取迭代。

显然, join的参数是[ str(_) for _ in xrange(10) ] x [ str(_) for _ in xrange(10) ] ,这是一个列表理解 。

看这个:

 >>>''.join( str(_) for _ in xrange(10) ) '0123456789' 

现在, str(_) for _ in xrange(10) ,no []join的参数就是str(_) for _ in xrange(10) ,但结果是一样的。

为什么? str(_) for _ in xrange(10)是否也产生一个列表或一个迭代?

 >>>''.join( str(_) for _ in xrange(10) ) 

这被称为生成器expression式 ,在PEP 289中进行了解释。

生成器expression式与列表parsing的主要区别在于前者不会在内存中创build列表。

请注意,还有第三种方式来编写expression式:

 ''.join(map(str, xrange(10))) 

其他受访者在回答您已经发现了一个生成器expression式 (与列表parsing相似但没有周围的方括号)时是正确的。

一般来说,genexps(因为他们是深情的知道)更有记忆效率和速度比列表理解。

但是, ''.join()的情况下,列表理解既快速又高效。 原因在于连接需要对数据进行两次传递,所以实际上需要一个真正的列表。 如果你给它一个,它可以立即开始工作。 如果你给它一个genexp,它不能开始工作,直到它通过运行genexp来耗尽,在内存中build立一个新的列表:

 ~ $ python -m timeit '"".join(str(n) for n in xrange(1000))' 1000 loops, best of 3: 335 usec per loop ~ $ python -m timeit '"".join([str(n) for n in xrange(1000)])' 1000 loops, best of 3: 288 usec per loop 

比较itertools.imapmap时,结果是一样的:

 ~ $ python -m timeit -s'from itertools import imap' '"".join(imap(str, xrange(1000)))' 1000 loops, best of 3: 220 usec per loop ~ $ python -m timeit '"".join(map(str, xrange(1000)))' 1000 loops, best of 3: 212 usec per loop 

你的第二个例子使用生成器expression式而不是列表理解。 与列表理解不同的是,列表完全构build并传递给.join() 。 使用生成器expression式,项目将逐个生成并由.join()消耗。 后者使用更less的内存,通常更快。

碰巧,列表构造函数将愉快地使用任何迭代,包括一个生成器expression式。 所以:

 [str(n) for n in xrange(10)] 

仅仅是“语法糖”:

 list(str(n) for n in xrange(10)) 

换句话说,列表理解只是一个变成列表的生成器expression式。

如前所述,这是一个生成器expression式 。

从文档:

只有一个参数的调用可以省略括号。 请参阅呼叫以获取详细信息。

如果它是在parens中,而不是括号,它在技术上是一个生成器expression式。 生成器expression式首先在Python 2.4中引入。

http://wiki.python.org/moin/Generators

连接之后的部分( str(_) for _ in xrange(10) )本身就是一个生成器expression式。 你可以做这样的事情:

 mylist = (str(_) for _ in xrange(10)) ''.join(mylist) 

这意味着你在上面的第二种情况下写的是完全一样的东西。

生成器有一些非常有趣的属性,不是最不重要的是,当你不需要分配整个列表时,它们不会最终分配一个完整的列表。 相反,像join这样的function将这些项目从发生器expression式中逐个“抽出”,并且在微小的中间部件上进行工作。

在你的具体例子中,列表和生成器可能不会有太大的不同,但是一般来说,我更喜欢使用生成器expression式(甚至是生成器函数),主要是因为生成器比完整列表物化。

这是一个生成器,而不是一个列表理解。 生成器也是可迭代的,但是不是首先创build整个列表,然后传递它join,它将逐个传递xrange中的每个值,这可以更有效。

第二次join调用的参数是一个生成器expression式。 它确实产生了一个迭代。