0%

python列表解析和生成器表达式

在python中经常可以看到一些很精简的写法,与以往接触的其他语言不同的用法。有两种常见的,列表解析和生成器表达式。

列表解析(List comprehensions)

首先我们看一下列表解析的语法。

[expr for iter_var in iterable]
[expr for iter_var in iterable if cond_expr]

for 循环迭代iterable对象所有的条目,前面的expr应用于序列的每个成员,最后的结果值是该表达式产生的列表。
比如

1
print [x ** 2 for x in range(6)]

输出[0, 1, 4, 9, 16, 25]
其实这种用法和分开写是一样的,比如

1
2
res = [(i, j) for i in range(5) for j in range(3) if (i+j)%2 == 0]
print res

1
2
3
4
5
6
res = []
for i in range(5) :
for j in range(3):
if (i+j)%2 == 0:
res.append((i, j))
print res

输出是一样的
[(0, 0), (0, 2), (1, 1), (2, 0), (2, 2), (3, 1), (4, 0), (4, 2)]

生成器表达式(Generator Expressioins)

它是列表解析的一个扩展,至于用法和上面非常相似

(expr for iter_var in iterable)
(expr for iter_var in iterable if cond_expr)

不过他们还是有很大不同的,列表解析要一次性生成所有的数据,用以创建整个列表。而生成器表达式不是这样的。

生成器表达式不是正真创建数字列表,而是返回一个生成器,这个生成器会把每次计算出一个条目之后,把这个条目yield产生出来。生成器表达式使用了**延迟计算(lazy evaluation)**,所以它在占用内存方面更有效。在使用上和列表解析基本相同,只是一个占用内存更少的一个结构。

Tips

  • 使用列表解析完成的功能,也可以使用map、filter、lambda来实现。比如实现上面计算平方,map(lambda x: x**2, range(6))
    然而,使用列表解析比这种用法效率更高。
  • 当序列过长,每次只需要一个元素时,使用生成器表达式较优。
  • 当执行类似复制列表操作时,直接方式实现比使用列表解析更好。
    L1 = list(L2) ,不必使用 L1 = [i for i in L2]