在Python中没有[]的列表理解

List comprehension without [ ] in Python

加入列表:

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

必须把安join迭代变量。

apparently [ str(_) for _ in xrange(10) ]join’s,和它的参数是一个列表,阅读能力。

看看这个:

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

现在的问题是,join’s Just str(_) for _ in xrange(10)[],但结果是相同的。

为什么?str(_) for _ in xrange(10)也产生不安或迭代变量的列表?


其他受访者的回答是正确的,你发现了一个生成器表达式(它有一个类似于列表理解的符号,但没有周围的方括号)。

一般来说,genepxps(它们被亲切地称为genepxps)比列表理解更高效、更快。

然而,在''.join()的情况下,列表理解既更快,也更节省内存。原因是join需要对数据进行两次传递,所以它实际上需要一个真正的列表。如果你给它一个,它可以立即开始工作。如果您给它一个genexp,它将无法开始工作,直到它通过运行genexp来耗尽内存中的新列表:

1
2
3
4
~ $ 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.imap与map进行比较时,也会得到相同的结果:

1
2
3
4
~ $ 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


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

这被称为生成器表达式,并在PEP289中解释。

生成器表达式和列表理解之间的主要区别在于前者不会在内存中创建列表。

请注意,有第三种方法可以编写表达式:

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


第二个示例使用生成器表达式,而不是列表理解。不同的是,通过清单理解,清单被完全构建并传递给.join()。使用生成器表达式,项目逐个生成,并由.join()使用。后者使用更少的内存,通常更快。

碰巧的是,列表构造函数将很乐意使用任何iterable,包括生成器表达式。所以:

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

只是"句法糖"的意思:

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

换句话说,列表理解只是一个生成器表达式,它被转换成一个列表。


如前所述,它是一个生成器表达式。

从文档中:

The parentheses can be omitted on calls with only one argument. See section Calls for the detail.


如果它在parens中,而不是括号中,从技术上讲它是一个生成器表达式。在python 2.4中首次引入了生成器表达式。

http://wiki.python.org/moin/generators网站

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

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

它的意思和你在上面第二个案例中写的完全一样。

生成器有一些非常有趣的属性,最不重要的是,当您不需要时,它们最终不会分配整个列表。相反,一个像join"pumps"这样的函数一次从生成器表达式中抽取一个项目,对微小的中间部分进行处理。

在您的特定示例中,list和generator的执行方式可能没有太大的不同,但一般来说,我更喜欢在任何时候使用generator表达式(甚至是generator函数),这主要是因为对于一个generator来说,要比完整的列表物化慢一些是非常罕见的。


第二个join调用的参数是一个生成器表达式。它确实产生了一个不可测的。


这是一个生成器,而不是列表理解。生成器也是iterables,但它不会先创建整个列表,然后将其传递给join,而是逐个传递xrange中的每个值,这样效率会更高。