Post

【Python 高级特性】推导式:一行更比三行强,用更少的代码写出更高的效率

Hi 朋友们,我会用一系列文章展示 Python 高级特性,这篇文章是系列的第一篇。

Python 高级特性是 Python 中相对于基础写法更加高效的特性。如果你刚刚学完 Python 的基础语法,那么我非常推荐你学习这些高级特性。它有一点学习成本,但能极大提升代码效率,原本需要一天才能完成的代码,如果你熟练使用高级特性,可以压缩到一小时完成。

今天我想要分享的内容是推导式。推导式是一种高效创建列表、字典、集合或其他可迭代对象的方式,常规方法需要 3 行才能完成的功能,使用推导式仅需要 1 行。

你会在下面的例子中看到,如何构造推导式和推导式的优势。

现在让我们开始吧!

列表推导式

基础使用

第一个例子很简单,仅仅是复制了一个列表。

1
2
3
4
5
6
nums = [0,1,2,3,4,5]

my_list = []
for i in nums:
    my_list.append(i)
print(my_list)

让我们看看常规方法是怎么做的,首先创建一个新列表,然后使用 for 循环遍历原有列表中的每个元素,再将每个元素都添加到新列表中。

下面是列表推导式的写法。

1
2
my_list = [i for i in nums]
print(my_list)

看,原本需要三行才能完成的功能,通过列表推导式,一行就够了。

现在让我们来看一下列表推导式的构造。两边的方括号意味着我们正在构造一个列表,最前面的 i 是要放在新列表中的元素,后面的 for i in nums 告诉我们,inums 中的每个元素。

这是一个非常简单的列表推导式,我希望这个例子能让你看到列表推导式很好写,也很有用。

现在让我们看另一个稍微复杂一点的例子。

加入操作

现在,我们需要创建一个新列表,存储原有列表中每个数字的平方。

1
2
3
4
5
6
nums = [0,1,2,3,4,5]

my_list = []
for i in nums:
    my_list.append(i**2)
print(my_list)

与上一个例子相比,只改动了一个地方。添加到新列表中的不再是 i ,变成了 i**2

如果使用列表推导式,也只需要改动一个地方。

1
2
my_list = [i**2 for i in nums]
print(my_list)

将最前面的 i 改为 i**2,意味着需要放在列表中的是 i 的平方。后面的 for i in nums 与之前的例子一样,告诉我们 inums 中的每个元素。

让我们继续,看看下一个更复杂一点的例子。

加入条件

现在,我只想将列表中偶数平方,而不是每个元素都平方。

1
2
3
4
5
6
7
nums = [0,1,2,3,4,5]

my_list = []
for i in nums:
    if i % 2 == 0:
        my_list.append(i**2)
print(my_list)

在上一个例子的基础上, for 循环内添加了if 语句,对 nums 中的每个元素判断是否为偶数。

以下是使用列表推导式的写法。

1
2
my_list = [i**2 for i in nums if i % 2 == 0]
print(my_list)

和常规写法的顺序一致,都是在 for 循环后添加了 if 语句用于判断。

如果我想更复杂一点点,在推导式中加入 else 语句,那么顺序就会有所改变,比如下面的代码。

1
my_list = [i**2 if i % 2 == 0 else i**3 for i in nums]

先是 if...else 结构,然后才是 for 语句。顺序刚好与上面先 forif 相反,对于新手来说并不友好。所以,在你能够熟练使用列表推导式之前,我不建议在列表推导式中加入 else 语句。

接下来,是一个更复杂的列表推导式。

嵌套 loop

现在我想要一个元组组成的列表。这个元组的两个元素分别来自两个列表。一个列表是 ['a', 'b', 'c'],另一个是 [1, 2, 3]。也就是说,我希望得到 [(a1), (a2), (a3), (b1), (b2), (b3), (c1), (c2), (c3)]这样的列表。

1
2
3
4
5
6
7
8
letters = ['a', 'b', 'c']
nums = [1, 2, 3]

my_list = []
for i in letters:
    for j in nums:
        my_list.append((i, j))
print(my_list)

常规写法使用了两个 for 循环嵌套,在列表推导式中也是一样。

1
2
my_list = [(i, j) for i in letters for j in nums]
print(my_list)

列表推导式中的两个 for 顺序与常规语句一样。前面的 for 是外循环,里面的 for 是内循环。

除了列表,字典和集合也可以使用推导式,它们的语法基本一致,只有细微的差别。让我们来看看。

字典推导

以下语句展示了如何 for 循环两个列表来创建一个字典。

1
2
3
4
5
6
7
letters = ['a', 'b', 'c']
nums = [1, 2, 3]

my_dict = {}
for i, j in zip(letters, nums):
    my_dict[i] = j

zip 函数的功能是将两个列表中的元素一一对应起来,返回一个元组构成的可迭代对象。在这个例子中,zip 函数返回的是 ('a', 1), ('b', 2), ('c', 3)

上述代码先创建一个空字典,然后使用 for 循环遍历每个元组,将元组的第一个元素作为 key,第二个元素作为 value,添加到空字典中。

现在我将使用推导式进行改写。

1
2
my_dict = {i:j for i, j in zip(letters, nums)}

集合推导

集合是一种相对字典和列表没那么常见的数据类型,特点是无序且不重复。当你想要去除一个列表中的重复元素时,就会用到集合。 集合推导式的写法与列表推导式非常相似,下面的语句根据一个列表新建了一个集合。

1
2
3
4
5
6
l = [1, 2, 3, 4, 5, 5, 5, 6, 6, 7, 8, 9]

my_set = set()
for i in l:
    my_set.add(i)

首先创建一个空集合,然后使用 for 循环遍历 l,将每个元素添加到 my_set 中。

现在我将使用推导式进行改写。

1
2
my_set = {i for i in l}

与列表推导唯一的不同仅在于将方括号换成了花括号。

最后

通过这篇内容,你会发现,列表推导式、字典推导式、集合推导式的写法写起来非常简单,作用却非常大。现在你可以浏览你的代码并用这些推导式来替换一些臃肿的 for 循环,这一定会让你的代码更上一层楼。 如果你还有其他的问题,欢迎在评论区留言,我会尽快回复。 如果你觉得这篇文章对你有帮助,欢迎点赞分享。也欢迎关注我的频道,我会持续更新 Python 相关的内容。感谢你的阅读。

This post is licensed under CC BY 4.0 by the author.