查看全课大纲(第 21 / 51 节)
- 1.Python 是什么?为什么值得学?
- 2.如何为 Python 编程准备一个“全家桶”环境?
- 3.Python 有哪几种执行方法?
- 4.行与缩进到底有什么用?
- 5.注释有什么用,怎么写?
- 6.变量:如何给数据起个好名字?
- 7.运算符的优先级和常见坑点是什么?
- 8.Python 中,数字和布尔值究竟有哪几种?
- 9.输入函数 `input()` 和文件读取 `open()` 怎么用?
- 10.如何将程序的结果展示给用户或保存下来?
- 11.CSV 文件怎么读怎么写才方便?
- 12.列表是什么,如何创建和访问它?
- 13.列表的修改操作,有哪些方法?
- 14.列表切片为什么能取到部分元素?排序和查找又该怎么用?
- 15.判断语句:如何让程序根据条件做不同的事?
- 16.for 循环如何遍历序列中的元素?
- 17.while 循环什么时候才会停?
- 18.while 循环的结束条件,你写对了吗?
- 19.循环中途想提前结束,怎么办?
- 20.`break` 和 `continue` 到底有什么区别?
- 21.列表推导式如何让代码更简洁高效?
- 22.字符串怎么定义、拼接和操作?
- 23.元组:为什么定义单个元素时要加逗号?
- 24.集合(set)怎么用?如何快速去重和做集合运算?
- 25.字典是什么,为什么比列表更方便?
- 26.字典的增删改查与遍历,如何避免 KeyError?
- 27.函数里的变量,为什么有的能用有的不能用?
- 28.在函数内部修改全局变量,为什么有时不生效?
- 29.函数里能修改全局变量吗?返回值怎么用?
- 30.匿名函数:如何用 lambda 快速定义简单函数?
- 31.面向对象编程是什么,为什么需要它?
- 32.类中的方法和属性到底怎么定义和使用?
- 33.如何控制对对象内部属性和方法的访问?
- 34.异常发生时,程序会怎样继续执行?
- 35.如何组织代码:包和模块
- 36.`if __name__ == '__main__'` 到底有什么用?
- 37.如何用 IDE 的 Debug 功能排查程序错误?
- 38.Matplotlib 绘图的第一步该做什么?
- 39.Figure 是什么,如何设置图形尺寸?
- 40.如何自定义 Matplotlib 的坐标轴?
- 41.如何为图表添加图例,让不同曲线一目了然?
- 42.饼图怎么画才能直观展示数据占比?
- 43.如何用 Matplotlib 绘制散点图?
- 44.柱状图怎么画?
- 45.如何使用 Matplotlib 绘制等高线图?
- 46.如何在 Matplotlib 中绘制子图?
- 47.zip 函数如何把多个列表“打包”在一起?
- 48.如何给可迭代对象加上索引?
- 49.random 模块如何生成随机数?
- 50.math 模块怎么用?
- 51.Counter 如何快速统计元素出现次数?
列表推导式如何让代码更简洁高效?
约 11 分钟
小象实战讲义 · Python 编程从入门到实践
在掌握了 for 循环和 if 条件判断之后,我们常常会遇到这样的需求:从一个列表筛选出某些元素,或者对列表中的每个元素进行计算,最终生成一个新的列表。本节要学习的列表推导式(list comprehension),正是解决这类问题的“语法糖”。它能将多行循环代码压缩成一行,让代码更简洁。本节是《控制流》章节的重要一环,它建立在 for 循环和 if 条件判断的基础之上。
💡 核心导读
- 是什么:列表推导式是一种从现有序列(如列表)构造新列表的简洁写法。
- 怎么用:基本格式为
[表达式 for 变量 in 序列 if 条件],其中if条件可以省略。 - 优点:相比传统
for循环,代码更简洁,处理较大数据量时耗时通常也更少。 - 注意点:
if放在不同位置含义不同——放在for后面是过滤,if...else放在for前面是分支计算。
列表推导式的基本结构
列表推导式的基本格式如下:
新列表 = [表达式 for 临时变量 in 输入序列 if 过滤条件]- 最外层的方括号
[]:表示最终生成的结果是一个列表。 for 临时变量 in 输入序列:与普通for循环的写法相同,用于遍历序列中的每一个元素,并把当前元素赋给临时变量。表达式:临时变量参与这个表达式的计算,计算结果成为新列表中的一个元素。if 过滤条件(可选):只有满足条件的元素,才会参与表达式计算并放进新列表。
简单来说,列表推导式的工作流程是:遍历序列 → 条件筛选(可选)→ 计算表达式 → 收集结果。
从基础示例看推导式的优势
假设我们需要生成一个包含 0 到 29 之间所有偶数的列表。先用传统的 for 循环,再用列表推导式,对比如下:
# 传统 for 循环方法
multiples = []
for i in range(30):
if i % 2 == 0:
multiples.append(i)
print("传统 for 循环:", multiples)
# 列表推导式方法
multiples_comprehension = [i for i in range(30) if i % 2 == 0]
print("列表推导式:", multiples_comprehension)传统 for 循环: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28]
列表推导式: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28]两种写法的结果完全一致,但列表推导式只用了一行。除了简洁,它在数据量较大时通常也更快(具体差异会随机器和 Python 版本不同而变化)。
在推导式中使用复杂表达式
列表推导式中的“表达式”可以是任何有效的 Python 表达式,包括函数调用。
# 定义一个求平方的函数
def squared(x):
return x * x
# 方式1:调用自定义函数,取 0~29 之间的偶数并求平方
even_squares = [squared(i) for i in range(30) if i % 2 == 0]
print("调用函数:", even_squares)
# 方式2:直接把计算式写在推导式里,效果相同
even_squares_direct = [i * i for i in range(30) if i % 2 == 0]
print("直接计算:", even_squares_direct)调用函数: [0, 4, 16, 36, 64, 100, 144, 196, 256, 324, 400, 484, 576, 676, 784]
直接计算: [0, 4, 16, 36, 64, 100, 144, 196, 256, 324, 400, 484, 576, 676, 784]对于简单计算,直接写表达式即可,不必专门定义函数;表达式较复杂或需要复用时,再抽成函数会更清晰。
处理带 else 分支的条件
前面的 if 都用作过滤:只让符合条件的元素参与计算。如果我们要根据元素的不同情况计算不同的结果,就需要用到 if...else,并且语法位置会发生变化。
场景:对 0 到 19 之间的数字,偶数放入它的平方,奇数放入它的立方。
# 注意:if...else 是表达式的一部分,要放在 for 前面
output_list = [x ** 2 if x % 2 == 0 else x ** 3 for x in range(20)]
print(output_list)[0, 1, 4, 27, 16, 125, 36, 343, 64, 729, 100, 1331, 144, 2197, 196, 3375, 256, 4913, 324, 6859]验证一下:2 是偶数,平方为 4;3 是奇数,立方为 27;4 是偶数,平方为 16;5 是奇数,立方为 125,结果符合预期。
关键区别:
[x for x in seq if cond]:if在for之后,只用于过滤元素。[expr1 if cond else expr2 for x in seq]:if...else在for之前,是表达式的一部分,为每个元素选择不同的计算方式。
📝 动手练一练
- 有一个字符串列表
words = ["apple", "banana", "cherry", "date", "elderberry"],请使用列表推导式生成一个新列表,只包含长度大于 5 的单词,并将这些单词转换为大写。
👉 点击查看参考答案
思路:遍历 words,用 if 判断单词长度,对符合条件的单词调用 .upper() 转成大写。
words = ["apple", "banana", "cherry", "date", "elderberry"]
long_words_upper = [word.upper() for word in words if len(word) > 5]
print(long_words_upper)['BANANA', 'CHERRY', 'ELDERBERRY']- 给定数字列表
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],请使用列表推导式生成一个新列表:偶数乘以 10,奇数保持不变。
👉 点击查看参考答案
思路:需要根据条件选择不同表达式,应使用 表达式1 if 条件 else 表达式2,并把它放在 for 之前。
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = [num * 10 if num % 2 == 0 else num for num in numbers]
print(result)[1, 20, 3, 40, 5, 60, 7, 80, 9, 100]常见错误
| 错误写法 | 现象或报错 | 原因 | 正确写法 |
|---|---|---|---|
new_list = [i for i in range(10) i % 2 == 0] | SyntaxError: invalid syntax | for 部分和过滤条件之间缺少 if 关键字。 | new_list = [i for i in range(10) if i % 2 == 0] |
new_list = [i if i % 2 == 0 for i in range(10)] | SyntaxError: expected 'else' after 'if' expression | 把 if...else 当作过滤条件时,必须写完整的 else 分支,并且整个 if...else 表达式要放在 for 之前。 | new_list = [i if i % 2 == 0 else 0 for i in range(10)] |
result = [i for i in range(3)]print(i) | NameError: name 'i' is not defined. Did you mean: 'id'? | 推导式中的临时变量只在推导式内部有效,循环结束后不能再访问。 | 需要用到元素时,在推导式内部完成计算;或改用普通 for 循环。 |
小结
- 列表推导式
[表达式 for 变量 in 序列 if 条件]是一种快速构建新列表的简洁语法。 - 它的主要优点是代码简洁;处理较大数据量时,耗时通常也比等价的
for循环更少。 if放在for之后用于过滤元素;if...else放在for之前作为表达式的一部分,为不同元素选择不同计算方式。- 推导式中的“表达式”可以是简单运算,也可以是函数调用。
- 推导式中的临时变量只在推导式内部有效,循环结束后无法再访问。
📋 行动清单
- 将本节“动手练一练”的题目用传统
for循环重写一遍,对比两种写法的差异。 - 尝试用列表推导式,把你之前练习中的某个
for循环生成列表的代码改写一遍。 - 思考:如果要生成一个字典(键为数字,值为该数字的平方),能否借鉴列表推导式的写法?本课不展开其他推导式。
—— 小象教研组
配套资料 · 直接下载
课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。
- 下载第2章代码包:列表推导式_样例代码(含1 个 Notebook)ZIP · 763B