考虑以下玩具示例:
>>> def square(x): return x*x
...
>>> [square(x) for x in range(12) if square(x) > 50]
[64, 81, 100, 121]
我必须在列表理解中打两次方格(X)。这种复制很难看,很容易出错(在修改代码时很容易更改这两个调用中的一个),而且效率很低。
我当然可以这么做:
>>> squares = [square(x) for x in range(12)]
>>> [s for s in squares if s > 50]
[64, 81, 100, 121]
或者这个:
[s for s in [square(x) for x in range(12)] if s > 50]
这两者都是可居住的,但似乎有一种方法可以在一条语句中完成这一切,而不必嵌套两个列表理解,我知道,下次我读代码时,我得盯着它看一段时间,才能弄清楚到底发生了什么。有办法吗?
我想问我一个公平的问题,就是我想象这样的语法会是什么样子。这里有两个想法,但在Python中既不习惯(也不起作用)。他们受到Lisp中的回指宏的启发。
[square(x) for x in range(12) if it > 50]
[it=square(x) for x in range(12) if it > 50]
发布于 2013-11-20 00:38:33
您应该使用生成器:
[s for s in (square(x) for x in range(12)) if s > 50]
这避免了创建一个未过滤的中间方格列表。
发布于 2013-11-20 01:31:23
下面是嵌套生成器与“链式”列表比较和计算两次
$ python -m timeit "[s for n in range(12) for s in [n * n] if s > 50]"
100000 loops, best of 3: 2.48 usec per loop
$ python -m timeit "[s for s in (x * x for x in range(12)) if s > 50]"
1000000 loops, best of 3: 1.89 usec per loop
$ python -m timeit "[n * n for n in range(12) if n * n > 50]"
1000000 loops, best of 3: 1.1 usec per loop
$ pypy -m timeit "[s for n in range(12) for s in [n * n] if s > 50]"
1000000 loops, best of 3: 0.211 usec per loop
$ pypy -m timeit "[s for s in (x * x for x in range(12)) if s > 50]"
1000000 loops, best of 3: 0.359 usec per loop
$ pypy -m timeit "[n * n for n in range(12) if n * n > 50]"
10000000 loops, best of 3: 0.0834 usec per loop
我使用n * n
而不是square(n)
,因为它很方便,并且从benckmark删除了函数调用的开销。
TLDR:对于简单的情况,最好只是重复计算。
发布于 2013-11-20 00:43:11
另一种选择是使用“链式”列表复式,而不是嵌套式:
[s for n in range(12) for s in [square(n)] if s > 50]
不过,可能是个奇怪的读物。
https://stackoverflow.com/questions/20085164
复制相似问题