惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
WordPress大学
WordPress大学
Google DeepMind News
Google DeepMind News
T
The Exploit Database - CXSecurity.com
阮一峰的网络日志
阮一峰的网络日志
F
Fox-IT International blog
The GitHub Blog
The GitHub Blog
Engineering at Meta
Engineering at Meta
I
Intezer
P
Privacy & Cybersecurity Law Blog
B
Blog RSS Feed
Latest news
Latest news
小众软件
小众软件
A
Arctic Wolf
Attack and Defense Labs
Attack and Defense Labs
L
LINUX DO - 热门话题
博客园 - 聂微东
B
Blog
T
Troy Hunt's Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
Malwarebytes
Malwarebytes
爱范儿
爱范儿
Recorded Future
Recorded Future
Apple Machine Learning Research
Apple Machine Learning Research
人人都是产品经理
人人都是产品经理
D
Docker
T
Threat Research - Cisco Blogs
MyScale Blog
MyScale Blog
Martin Fowler
Martin Fowler
E
Exploit-DB.com RSS Feed
F
Fortinet All Blogs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
PCI Perspectives
PCI Perspectives
Scott Helme
Scott Helme
N
Netflix TechBlog - Medium
博客园 - 三生石上(FineUI控件)
T
True Tiger Recordings
C
Check Point Blog
Microsoft Azure Blog
Microsoft Azure Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
K
Kaspersky official blog
Security Latest
Security Latest
The Hacker News
The Hacker News
Microsoft Security Blog
Microsoft Security Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
Stack Overflow Blog
Stack Overflow Blog
S
Security @ Cisco Blogs
C
CXSECURITY Database RSS Feed - CXSecurity.com
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
M
Microsoft Research Blog - Microsoft Research

掘金

从“连接不上”到“交易成功”:我用 @solana/web3.js 在 React 中搞定 Solana 钱包交互的全过程 juejin.cn 海量人群包存储优化:基于 RoaringBitmap 交换格式与 Redis 分片 Bitmap 的实践 juejin.cn juejin.cn 鸿蒙项目首页启动链路与 ArkUI 架构学习总结 如何手写一个 AI Agent 工具调用循环(Tool Loop) Tauri 应用首次上架 App Store 被驳回了 3 次(iOS)和 12 轮(macOS)的经历 juejin.cn Flutter 桌面小组件开发 现代多模态大模型的核心基础:Unified Self-Attention juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn Transformer 原论文怎么训出来的:8 张 P100、12 小时、warmup 4000 步 Hermes 升级后,我的 Telegram 附件突然发不出来了 Transformer 中的前馈网络:那个看似平平无奇的两层 MLP,其实是「记忆」所在 AI Coding开始进入第四个时代,我还没上车呢! 【Agentic RL / 强化学习 / OPD】OpenClaw-RL 源码阅读笔记 --- (1)---基础 juejin.cn Vibe Coding 全栈实战:章鱼哥解题 01|搭好产品底座与登录链路 juejin.cn 我让 AI 加了一个开关,结果代码走了原本不该走的分支 Manim物理模拟:别自己写欧拉了! 我也该升级了,陪伴了我7年的博客 juejin.cn juejin.cn MCP 高德地图实战:当 AI 学会使用工具,一个协议如何重塑大模型的行动边界 用魔法打败魔法:我让AI替我去面试前端岗,AI面试官给我打了92分,还发了offer juejin.cn juejin.cn juejin.cn juejin.cn Android Input Spy Window Claude Code CLI 命令大全:60 个原生命令一次讲清 juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn 关于一个新手小白靠claude帮助下的全栈留言板项目开发 juejin.cn juejin.cn juejin.cn 从本地开发到生产部署:用 Docker Compose 跑通 NestJS、MySQL 与 Milvus AI应用开发七:可以替代 RAG 的技术 juejin.cn 小书匠:一款本地优先、去中心化的全能笔记软件 juejin.cn juejin.cn juejin.cn Shadow实战接入与生产落地:从零搭建到稳定运行 Shadow Transform:编译期的魔法——字节码替换实战 juejin.cn juejin.cn Hermes Agent:一个真正“会成长”的开源 AI Agent,正在改变 AI 自动化玩法 juejin.cn juejin.cn juejin.cn 残差连接:为什么深层网络必须留一条直路 juejin.cn FastAPI 从入门到实战:3 分钟构建高性能异步 API juejin.cn juejin.cn CryptoJS:数据安全的JavaScript加密利器 juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn ArkClaw AI 盯盘管家 —— 从手动口令到自动推送,4 套预置定时任务模版一键启用 juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn “杀!杀!杀!”、“我最讨厌事后道歉”——骂“杀哥”之前,谁还没当过情绪崩溃的人
Python的列表推导式里藏了个坑,差点让我加班到凌晨
2026-04-12 · via 掘金
  • Python的列表推导式里藏了个坑,差点让我加班到凌晨*

引言

列表推导式(List Comprehension)是Python中一种简洁而强大的语法特性,它允许开发者用一行代码生成列表,替代传统的for循环。由于其简洁性和高效性,列表推导式在Python社区中广受欢迎。然而,正是这种“简洁”背后,隐藏了一些容易被忽略的陷阱。

最近,我在一个项目中因为对列表推导式的理解不够深入,差点酿成大错,不得不加班到凌晨排查问题。本文将分享这段经历,并深入剖析列表推导式中容易被忽视的细节,尤其是变量作用域延迟绑定的问题。希望通过这篇文章,你能避免类似的坑。


列表推导式的基本用法

在深入问题之前,我们先回顾一下列表推导式的基本语法。列表推导式的典型结构如下:

[expression for item in iterable if condition]

例如,生成一个包含0到9的平方的列表:

squares = [x**2 for x in range(10)]

这种写法比传统的for循环更简洁,但它的行为并不总是直观的。


列表推导式的陷阱

陷阱1:变量作用域的泄露

在Python 2中,列表推导式中的循环变量会“泄露”到外部作用域。例如:

x = 10
squares = [x**2 for x in range(5)]
print(x)  # 在Python 2中输出4,在Python 3中输出10

在Python 2中,列表推导式结束后,x的值会被覆盖为range(5)的最后一个值(即4)。这种行为在Python 3中被修复,列表推导式中的变量不会泄露到外部作用域。

虽然Python 3已经修复了这个问题,但如果你还在维护Python 2的代码库(或者阅读旧代码),这一点需要特别注意。

陷阱2:延迟绑定与闭包问题

更隐蔽的问题是列表推导式在嵌套作用域中的行为,尤其是在结合lambda或生成器表达式时。考虑以下代码:

funcs = [lambda: x for x in range(3)]
print([f() for f in funcs])  # 输出[2, 2, 2],而不是[0, 1, 2]

这里,funcs是一个包含三个lambda函数的列表,每个函数理论上应该返回x的当前值(0、1、2)。但实际上,所有函数都返回2

  • 原因*:在列表推导式中,lambda函数并没有立即捕获x的值,而是引用了变量x本身。当lambda被调用时,x的值已经变成了range(3)的最后一个值(即2)。这种现象称为“延迟绑定”(Late Binding)。

  • 解决方法*:通过将x作为默认参数传递给lambda,可以立即绑定它的值:

funcs = [lambda x=x: x for x in range(3)]
print([f() for f in funcs])  # 输出[0, 1, 2]

陷阱3:列表推导式与生成器表达式的区别

列表推导式会立即生成一个列表,而生成器表达式(Generator Expression)是惰性求值的。在某些情况下,误用生成器表达式可能导致意想不到的结果。例如:

# 列表推导式
squares = [x**2 for x in range(5)]
print(squares)  # 输出[0, 1, 4, 9, 16]

# 生成器表达式
squares_gen = (x**2 for x in range(5))
print(squares_gen)  # 输出<generator object <genexpr> at 0x...>

如果误将生成器表达式当作列表推导式使用,可能会导致后续代码报错(例如尝试索引或切片)。


实际案例分析

在我的项目中,我需要动态生成一组函数,每个函数根据不同的参数执行不同的操作。最初我写了这样的代码:

actions = [lambda: print(f"Action {x}") for x in range(5)]
for action in actions:
    action()

我期望的输出是:

Action 0  
Action 1  
Action 2  
Action 3  
Action 4  

但实际输出却是:

Action 4  
Action 4  
Action 4  
Action 4  
Action 4  

所有的lambda函数都引用了最终的x值(4)。这个问题让我花了很长时间排查,因为它看起来非常违反直觉。

  • 修复方法*:
actions = [lambda x=x: print(f"Action {x}") for x in range(5)]
for action in actions:
    action()

通过将x作为默认参数绑定到lambda,我们确保了每个函数捕获的是当前的x值。


如何避免类似问题

  1. 理解变量作用域:在Python 3中,列表推导式的变量不会泄露到外部作用域,但在嵌套作用域中仍需小心延迟绑定问题。
  2. 使用默认参数绑定值:如果需要在lambda或闭包中捕获循环变量的值,务必通过默认参数绑定。
  3. 区分列表推导式和生成器表达式:明确两者的区别,避免误用。
  4. 编写单元测试:对于复杂的列表推导式或生成器表达式,编写测试用例验证行为是否符合预期。

总结

列表推导式是Python中非常强大的工具,但它并非没有陷阱。尤其是变量作用域和延迟绑定问题,可能导致难以调试的BUG。通过深入理解这些细节,并在实际编码中保持警惕,我们可以更安全地使用列表推导式,避免不必要的加班和调试痛苦。

希望这篇文章能帮助你避开类似的坑!