Blog·Tanky WooABOUTRSS

[翻译]Python: List Comprehensions

19 Apr 2012
这篇博客是从旧博客 WordPress 迁移过来,内容可能存在转换异常。

第一次翻译外文,虽然篇幅很小,但还是要纪念下。

原文:《Python: List Comprehensions

翻译:Tanky Woo

时间:2012.04.19

注意:以”>>>”和”…”开始的代码行表示Python的输入(它们是交互解释器的默认提示符)。其它的是Python的输出。

Python支持一种称为“列表推导式”的概念。它就像是一个数学家经常写的一样,可以用于以非常自然,简单的方式来构造列表。

下面是在数学中常用的描述列表list(或set集,元组tuple,向量vector)的方式。

S = {x² : x in {0 ... 9\}\}
V = (1, 2, 4, 8, ..., 2¹²)
M = {x | x in S and x even}

你大概在学校的数学课上了解过上面的式子。在Python中,你几乎直接可以以数学的方式来写这些表达式,而不需要去记住各种特殊晦涩的语法。

这是上面式子在Python中的表达:

>>> S = [x**2 for x in range(10)]
>>> V = [2**i for i in range(13)]
>>> M = [x for x in S if x % 2 == 0]
>>> 
>>> print S; print V; print M
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096]
[0, 4, 16, 36, 64]

我可以肯定你想要看一些更加复杂的样例。:) 接着来是另一种计算素数的方法。其中有趣的是我们先通过列表推导式构建一个非素数列表,然后通过另外一个列表推导式来获取逆序的列表,即素数列表。

>>> noprimes = [j for i in range(2, 8) for j in range(i*2, 50, i)]
>>> primes = [x for x in range(2, 50) if x not in noprimes]
>>> print primes
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]

注意(NB是Nota Bene的简写):你可以在一个列表推导式中嵌套另外一个列表推导式,这样在上面的例子中你就可以只写一个语句(而不用临时变量”noprimers”)。但这样表示导致语句太长,且没有可读性,所以并不推荐这种写法。

当然,列表推导式并不只适用于数字。列表可以包含任意类型的愿意,包括字符串,嵌套的列表,以及函数,你甚至可以在列表中混合不同的类型。

接下来的是作用在字符串列表上的列表推导式,并且生成一个列表的列表。每一个子列表都包含两个字符串和一个数字。

>>> words = 'The quick brown fox jumps over the lazy dog'.split()
>>> print words
['The', 'quick', 'brown', 'fox', 'jumps', 'over', 'the', 'lazy', 'dog']
>>> 
>>> stuff = [[w.upper(), w.lower(), len(w)] for w in words]
>>> for i in stuff:
...     print i
... 
['THE', 'the', 3]
['QUICK', 'quick', 5]
['BROWN', 'brown', 5]
['FOX', 'fox', 3]
['JUMPS', 'jumps', 5]
['OVER', 'over', 4]
['THE', 'the', 3]
['LAZY', 'lazy', 4]
['DOG', 'dog', 3]
>>> 
>>> stuff = map(lambda w: [w.upper(), w.lower(), len(w)], words)
>>> for i in stuff:
...     print i
... 
['THE', 'the', 3]
['QUICK', 'quick', 5]
['BROWN', 'brown', 5]
['FOX', 'fox', 3]
['JUMPS', 'jumps', 5]
['OVER', 'over', 4]
['THE', 'the', 3]
['LAZY', 'lazy', 4]
['DOG', 'dog', 3]

上面的例子也表明了你可以直接使用map()函数和lambda函数来实现相同的功能。但是有些情况你不能使用map()函数,而只能使用列表推导式来替代,或者恰恰相反。如果你可以同时使用这两种方式,则更加推荐使用列表推导式,因为大部分时候,它比map()+lambda更加高效,并且更加易于阅读。

如果通过for或if构建列表的规则太复杂而难以通过for或if语句来表达,或者如果构建规则会在运行时动态变化,则不建议使用列表推导式。在这些情况下,你最好通过一个合适的函数来使用map() 和/或 filter(),或者和列表推导式结合使用。