查看全课大纲(第 21 / 51 节)
  1. 1.Python 是什么?为什么值得学?
  2. 2.如何为 Python 编程准备一个“全家桶”环境?
  3. 3.Python 有哪几种执行方法?
  4. 4.行与缩进到底有什么用?
  5. 5.注释有什么用,怎么写?
  6. 6.变量:如何给数据起个好名字?
  7. 7.运算符的优先级和常见坑点是什么?
  8. 8.Python 中,数字和布尔值究竟有哪几种?
  9. 9.输入函数 `input()` 和文件读取 `open()` 怎么用?
  10. 10.如何将程序的结果展示给用户或保存下来?
  11. 11.CSV 文件怎么读怎么写才方便?
  12. 12.列表是什么,如何创建和访问它?
  13. 13.列表的修改操作,有哪些方法?
  14. 14.列表切片为什么能取到部分元素?排序和查找又该怎么用?
  15. 15.判断语句:如何让程序根据条件做不同的事?
  16. 16.for 循环如何遍历序列中的元素?
  17. 17.while 循环什么时候才会停?
  18. 18.while 循环的结束条件,你写对了吗?
  19. 19.循环中途想提前结束,怎么办?
  20. 20.`break` 和 `continue` 到底有什么区别?
  21. 21.列表推导式如何让代码更简洁高效?
  22. 22.字符串怎么定义、拼接和操作?
  23. 23.元组:为什么定义单个元素时要加逗号?
  24. 24.集合(set)怎么用?如何快速去重和做集合运算?
  25. 25.字典是什么,为什么比列表更方便?
  26. 26.字典的增删改查与遍历,如何避免 KeyError?
  27. 27.函数里的变量,为什么有的能用有的不能用?
  28. 28.在函数内部修改全局变量,为什么有时不生效?
  29. 29.函数里能修改全局变量吗?返回值怎么用?
  30. 30.匿名函数:如何用 lambda 快速定义简单函数?
  31. 31.面向对象编程是什么,为什么需要它?
  32. 32.类中的方法和属性到底怎么定义和使用?
  33. 33.如何控制对对象内部属性和方法的访问?
  34. 34.异常发生时,程序会怎样继续执行?
  35. 35.如何组织代码:包和模块
  36. 36.`if __name__ == '__main__'` 到底有什么用?
  37. 37.如何用 IDE 的 Debug 功能排查程序错误?
  38. 38.Matplotlib 绘图的第一步该做什么?
  39. 39.Figure 是什么,如何设置图形尺寸?
  40. 40.如何自定义 Matplotlib 的坐标轴?
  41. 41.如何为图表添加图例,让不同曲线一目了然?
  42. 42.饼图怎么画才能直观展示数据占比?
  43. 43.如何用 Matplotlib 绘制散点图?
  44. 44.柱状图怎么画?
  45. 45.如何使用 Matplotlib 绘制等高线图?
  46. 46.如何在 Matplotlib 中绘制子图?
  47. 47.zip 函数如何把多个列表“打包”在一起?
  48. 48.如何给可迭代对象加上索引?
  49. 49.random 模块如何生成随机数?
  50. 50.math 模块怎么用?
  51. 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 之前,是表达式的一部分,为每个元素选择不同的计算方式。

📝 动手练一练

  1. 有一个字符串列表 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']
  1. 给定数字列表 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 syntaxfor 部分和过滤条件之间缺少 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
    下载