Logo
Section 1 / 5

列表推导式

学习如何使用列表推导式以清晰且声明式的方式创建列表。

导入

列表推导式

学习如何使用列表推导式以清晰且声明式的方式创建列表。

有时,创建一个具有特定内容的列表非常有用,例如基于另一个列表或可迭代对象生成。这可以通过循环实现,或者使用 map 函数。

列表推导式提供了一种替代方案,它比循环更具声明性,通常也比使用 map 函数更清晰。

除了列表推导式,还有类似的技巧可用于生成惰性迭代器(生成器推导式)、集合和字典,我们将在本章中一并介绍。

列表推导式示例

先从一个简单的例子开始:假设我们要创建一个长度为 100 的列表,其中包含字符串 '0' 到 '99'。有多种方法可以实现。首先,我们可以使用循环,如下所示:

1a = [] 2for i in range(100): 3 a.append(str(i)) 4 5print(a)

或者,我们可以使用 map,如下所示:

1a = list(map(str, range(100))) 2 3print(a)

现在来看列表推导式的写法:

1a = [str(i) for i in range(100)] 2 3print(a)

在所有情况下,结果都是一样的:一个包含 100 个字符串的列表,如下所示:

1['0', '1', '2', ..., '98', '99']

这三种解决方案都不算差。第一种方法最冗长,也最不具声明性。所谓“不具声明性”是什么意思?这是一个循环,恰好按照一个简单模式构建列表。但由于它是循环,它可能做任何事情。代码采用的是命令式风格,也就是说,它不仅告诉 Python 需要什么样的列表,还详细说明了如何创建这个列表。

命令式代码更加灵活,但当你只需要完成一些简单而重复的任务时,这种灵活性反而可能成为缺点。你必须仔细检查代码,确保它没有执行比你预期更复杂的操作。

map 的写法更具声明性。它表明你希望将 str 函数应用到 0 到 99 的数字上,并将结果构造成一个列表。这些都是标准的 Python 函数,以标准方式调用。在这个具体例子中,这种解决方案几乎没有可挑剔的地方。

最后一个例子使用了列表推导式。我个人认为 map 的写法略胜一筹,但差距不大。列表推导式正是为了从另一个可迭代对象创建列表而设计的,因此当你看到这种语法时,就能立刻明白代码的意图。

理解列表推导式最好的方式可能是将其读作一句英文句子,如下所示:

创建一个列表,包含 range(100) 中每个 i 值对应的 str(i)

再看一个不同的例子:我们想要取一个数字列表,并创建一个新的列表,其中每个数字四舍五入到最接近的 5 的倍数。以下是用循环实现的方式。注意,要四舍五入到最接近的 5,需要先除以 5,四舍五入到最近的整数,然后再乘以 5。

1k = [12, 33, 49, 57] 2a = [] 3for x in k: 4 a.append(round(x/5)*5) 5 6print(a)

使用 map,代码变为:

1k = [12, 33, 49, 57] 2a = list(map(lambda x: round(x/5)*5, k)) 3 4print(a)

而作为列表推导式,代码则简化为:

1k = [12, 33, 49, 57] 2a = [round(x/5)*5 for x in k] 3 4print(a)

在这种情况下,列表推导式的优势在于无需使用 lambda 函数,使代码略微更简洁。

归约可迭代对象

使用条件的列表推导式