加入名单:
>>> ''.join([ str(_) for _ in xrange(10) ])
'0123456789'
join
必须采用可迭代的方式。
显然,join
的论点是[ str(_) for _ in xrange(10) ]
,而且是list comprehension。
看看这个:
>>>''.join( str(_) for _ in xrange(10) )
'0123456789'
现在,join
的参数只是str(_) for _ in xrange(10)
,没有[]
,但结果是一样的。
为什么呢? str(_) for _ in xrange(10)
是否也生成列表或可迭代?
答案 0 :(得分:121)
其他受访者回答您发现了generator expression(其符号类似于列表推导但没有周围的方括号)是正确的。
一般来说,genexps(因为它们被亲切地知道)比列表推导更有效,速度更快。
但是,''.join()
的情况,列表理解更快,内存效率更高。原因是 join 需要对数据进行两次传递,因此它实际上需要一个真实的列表。如果你给它一个,它可以立即开始工作。如果你给它一个genexp代替它,它就无法开始工作,直到它通过运行genexp到耗尽来在内存中建立一个新的列表:
~ $ 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 时,结果相同:
~ $ 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 :(得分:54)
>>>''.join( str(_) for _ in xrange(10) )
这称为生成器表达式,在PEP 289中有解释。
生成器表达式和列表推导之间的主要区别在于前者不会在内存中创建列表。
请注意,第三种方法是编写表达式:
''.join(map(str, xrange(10)))
答案 2 :(得分:5)
您的第二个示例使用生成器表达式而不是列表推导。不同之处在于,使用列表推导,列表完全构建并传递给.join()
。使用生成器表达式,项目将逐个生成并由.join()
使用。后者使用较少的内存,通常更快。
实际上,列表构造函数将很乐意使用任何迭代,包括生成器表达式。所以:
[str(n) for n in xrange(10)]
只是“语法糖”:
list(str(n) for n in xrange(10))
换句话说,列表推导只是一个转换为列表的生成器表达式。
答案 3 :(得分:4)
如果它是parens而不是括号,那么技术上是一个生成器表达式。 Generator表达式最初是在Python 2.4中引入的。
http://wiki.python.org/moin/Generators
连接后的部分( str(_) for _ in xrange(10) )
本身就是一个生成器表达式。你可以这样做:
mylist = (str(_) for _ in xrange(10))
''.join(mylist)
这意味着你在上面第二个案例中写的完全一样。
生成器有一些非常有趣的属性,其中最重要的是,当你不需要时,它们不会最终分配整个列表。相反,像连接这样的函数一次一个地“泵出”生成器表达式中的项目,在微小的中间部分上进行工作。
在你的特定例子中,列表和生成器可能执行的方式不同,但总的来说,我更喜欢使用生成器表达式(甚至生成器函数),主要是因为生成器慢于而不是完整的列表实现。
答案 4 :(得分:4)
答案 5 :(得分:0)
这是一个生成器,而不是列表理解。生成器也是可迭代的,但不是先创建整个列表然后将其传递给join,而是逐个传递xrange中的每个值,这样效率会更高。
答案 6 :(得分:0)
第二个join
调用的参数是生成器表达式。它确实产生了一个可迭代的。