Python 列表推导式:语法、示例与何时避免使用

  1. 首页
  2. 博客
  3. 软件开发
软件开发

Python 列表推导式:语法、示例与何时避免使用

一步步学会 Python 列表推导式:用一行代码创建、过滤和转换列表,查看与循环对比的实测耗时,并了解什么时候普通 for 循环更易读。

阅读约 7 分钟
Python 列表推导式:语法、示例与何时避免使用
要点
  • 基本模式是 [表达式 for 元素 in 可迭代对象 if 条件]。
  • 末尾单独的 if 用来过滤;开头的 if-else 用来在两个值之间选择。
  • 在我们的测试中,列表推导式比使用 append 的循环快约 37%。
  • 数据量很大时改用生成器表达式;逻辑需要多个清晰步骤时改用普通循环。

Python 列表推导式可以用一行易读的代码,从任何可迭代对象创建新列表。你不必先建一个空列表、再循环并调用 append,只需描述想要的结果。

本指南从基本模式讲到过滤、嵌套循环,以及我们自己测得的耗时。如果你刚接触 Python,请先看我们的 Python 入门教程(英文),并通过虚拟环境指南(英文)保持环境整洁。

Python 列表推导式的语法

从左到右阅读:表达式说明每个新元素是什么样子,for 部分说明元素从哪里来。

squares = [x * x for x in range(6)]
print(squares)          # [0, 1, 4, 9, 16, 25]

names = [" Hi ", "  QA "]
clean = [n.strip().lower() for n in names]
print(clean)            # ['hi', 'qa']

用循环得到同样结果要多写三行。只要这一行仍然容易阅读,节省的就是它的价值所在。

用条件过滤元素

在循环后面加一个 if,只保留满足条件的元素。

evens = [x for x in range(10) if x % 2 == 0]
print(evens)            # [0, 2, 4, 6, 8]

带 if-else 的 Python 列表推导式

如果你想为每个元素都生成一个值,请把 if-else 放在 for 之前。这是初学者最容易出错的地方,因为把 else 放在末尾会导致语法错误。

labels = ["even" if x % 2 == 0 else "odd" for x in range(4)]
print(labels)           # ['even', 'odd', 'even', 'odd']

经验法则:末尾的 if 会删除元素,开头的 if-else 会改变元素。使用 if-else 时列表长度保持不变。

嵌套循环与展平

多个 for 子句的阅读顺序与嵌套循环相同。可以用它们展平嵌套列表或生成配对。

matrix = [[1, 2, 3], [4, 5, 6]]
flat = [n for row in matrix for n in row]
print(flat)             # [1, 2, 3, 4, 5, 6]

pairs = [(x, y) for x in range(1, 3) for y in "ab"]
print(pairs)            # [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')]

要转置矩阵,可以把一个推导式嵌套在另一个里面:[[r[i] for r in matrix] for i in range(3)] 得到 [[1, 4], [2, 5], [3, 6]]。两层是可读性开始下降前的实际上限。

字典、集合和生成器形式

换一种括号,同样的思路就能创建其他类型。

lengths = {w: len(w) for w in ["pip", "venv", "uv"]}   # {'pip': 3, 'venv': 4, 'uv': 2}
unique  = {len(w) for w in ["pip", "venv", "uv", "git"]}  # {2, 3, 4}
total   = sum(x * x for x in range(1_000_000))           # generator, no list

想比较这些类型本身,请看我们关于列表、元组、集合和字典的指南(英文)。

速度与内存:我们的实测结果

我们在 Python 3.13.6 上用 100,000 个整数测试了每种写法,取五次运行中的最佳值。你的数字会有所不同,但先后顺序是稳定的。

任务耗时
使用 append 的循环(每个元素翻倍)5.18 ms
列表推导式(每个元素翻倍)3.25 ms
list(map(lambda ...))6.50 ms
用循环过滤偶数3.62 ms
用推导式过滤偶数3.43 ms

推导式明显快于 append 循环,但当大部分时间花在条件判断上时,差距会缩小。在内存方面,包含一百万个翻倍整数的列表约占 8.4 MB,而对应的生成器对象只有 200 字节,因为它每次只产生一个值。

何时不要使用列表推导式

  • 你只需要副作用,例如打印或保存。请使用普通循环;推导式会构建一个没用的列表。
  • 逻辑包含多个步骤。如果需要第二个变量或 try,请写循环或小函数。
  • 数据量巨大。请使用生成器表达式,这样 Python 不必把整个列表放进内存。
  • 需要超过两个 for 子句。为了下一位读者,把它拆成有名字的步骤。

总结

当一行简短代码能准确表达你的意思时,就用 Python 列表推导式;否则用循环。先掌握基本模式,再加一个过滤条件,然后练习 if-else 形式,直到顺序变得自然。

常见问题

Python 中的列表推导式是什么?

它是一种简洁的创建列表的方式:对可迭代对象的每个元素应用一个表达式,并可用可选条件进行过滤。

如何在列表推导式中使用 if-else?

把条件表达式放在 for 子句之前,例如 ["even" if x % 2 == 0 else "odd" for x in nums]。简单过滤只需在循环后加一个 if。

列表推导式比 for 循环快吗?

通常更快。在我们对 100,000 个元素的测试中,它比使用 append 的循环快约 37%,但应首先考虑可读性。

列表推导式和生成器表达式有什么区别?

列表推导式一次性在内存中构建整个列表。生成器表达式使用圆括号,每次产生一个值,处理大数据时可节省内存。

可以嵌套列表推导式吗?

可以,用于展平或转置矩阵。请控制在两层以内,难以阅读时就改用循环。

继续学习(英文文章)

与 Stack Quora 合作

需要测试、WordPress 或 SEO 方面的帮助?

我们帮助团队交付更好的软件并让网站成长。告诉我们你在做什么,我们会给出清晰的下一步建议。

继续阅读

更多指南 测试、人工智能和现代开发

喜欢这篇文章吗?选择一个主题并直接跳至我们最新的教程。

人工智能

人工智能幻觉解释:语言模型为何会产生幻觉以及如何减少它

人工智能幻觉解释:它们是什么,为什么语言模型产生它们,常见类型,如何通过基础和提示来减少它们,以及我们进行的简单检查。

阅读文章 →
DevOps

环境变量解释:.env 文件、秘密和配置正确完成

使用我们运行的 Python 示例解释环境变量:读取和设置它们、为什么每个值都是字符串、.env 文件、进程继承、秘密和验证。

阅读文章 →
软件开发

API 速率限制解释:算法、标头和处理 429 错误

API 速率限制通过我们运行的模拟进行了解释:令牌桶、固定窗口、滑动窗口、429 响应、速率限制标头、带回退的重试和测试限制。

阅读文章 →
测试自动化

Python 中的模拟:unittest.mock、补丁以及导致测试谎言的错误

使用unittest.mock 在Python 中进行模拟,经过测试:模拟和return_value、side_effect、修补使用名称的位置、spec 和autospec、模拟日期以及常见错误。

阅读文章 →
软件测试

代码覆盖率解释:行覆盖率与分支覆盖率以及 100% 的真正含义

用真实的coverage.py运行来解释代码覆盖率:行、分支和条件覆盖率,阅读报告,为什么100%覆盖率仍然会错过错误,以及合理的目标。

阅读文章 →
数据库与 SQL

SQL 中的 DELETE、TRUNCATE 和 DROP:差异、回滚以及何时使用它们

DELETE、TRUNCATE 和 DROP 通过经过测试的 SQL 进行了解释:各自删除什么、回滚、触发器、身份重置、速度,以及 PostgreSQL、MySQL、SQL Server 和 SQLite 有何不同。

阅读文章 →
数据库与 SQL

SQL 视图解释:创建、使用和避免陷阱(附示例)

SQL 视图通过我们运行的查询进行解释:创建视图、实时结果、隐藏列、性能、可更新和物化视图、破坏的依赖关系和最佳实践。

阅读文章 →
软件开发

TypeScript 接口与类型:真正的差异,使用编译器进行测试

TypeScript 接口与类型,使用真实编译器进行检查:两者都可以做什么,只有一个可以做什么,声明合并,扩展与交集以及要遵循的简单规则。

阅读文章 →
软件开发

Python *args 和 **kwargs 解释:灵活的函数和清晰的示例

Python *args 和 **kwargs 用我们运行的代码进行了解释:打包和解包、参数顺序、仅关键字和仅位置参数、装饰器和常见错误。

阅读文章 →
软件开发

Python Lambda 函数:语法、实际用途以及何时不使用它们

Python lambda 函数用我们运行的代码进行了解释:语法、使用键排序、映射和过滤器、闭包、后期绑定陷阱,以及何时普通 def 是更好的选择。

阅读文章 →
人工智能

什么是人工智能代理?它们是如何工作的,只需运行一个简单的代理循环

什么是人工智能代理?关于代理循环、工具、内存和护栏的简单指南,以及我们运行的一个小型 Python 循环、真正的风险以及何时简单的聊天机器人是更好的选择。

阅读文章 →
DevOps

监控与可观察性:真正的区别,包括日志、指标和跟踪

监控与可观察性解释:已知和未知的故障、日志、指标和跟踪、检查事件演练、黄金信号、OpenTelemetry 和有用的警报。

阅读文章 →
DevOps

Docker Volumes 与 Bind Mounts:以正确的方式保留容器数据

Docker 卷与绑定挂载解释:为什么容器数据消失、命名卷、绑定挂载、tmpfs、Compose 示例、备份、权限以及何时使用它们。

阅读文章 →
测试自动化

TDD 与 BDD:主要区别、以两种方式构建的一个功能以及何时使用每种方式

TDD 与 BDD 的解释是通过一种双向构建的折扣功能:使用我们运行的代码进行红绿重构、Given-When-Then 场景、工具、权衡以及何时使用每种方案。

阅读文章 →
软件开发

Git merge 与 rebase 的区别:示例及如何选择

用真实的 log 输出、对比表、rebase 黄金法则和安全的团队工作流,讲清 Git merge 与 rebase 的区别。

阅读文章 →
软件开发

Python 列表推导式:语法、示例与何时避免使用

Python 列表推导式详解:语法、过滤、if-else、嵌套循环、实测耗时,以及何时普通 for 循环更合适。

阅读文章 →
数据库与 SQL

SQL JOIN 详解:附示例(INNER、LEFT、RIGHT、FULL)

通过示例表和查询,一步步讲解 SQL JOIN:INNER、LEFT、RIGHT、FULL、CROSS 和 SELF,并介绍常见错误与性能技巧。

阅读文章 →