为什么Python列表推导式会在内部创建函数?
为什么Python 3.10的列表推导式要创建单独的函数对象?
问题背景
以下是Python 3.10中列表推导式的反汇编结果:
Python 3.10.12 (main, Jun 11 2023, 05:26:28) [GCC 11.4.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import dis >>> >>> dis.dis("[True for _ in ()]") 1 0 LOAD_CONST 0 (<code object <listcomp> at 0x7fea68e0dc60, file "<dis>", line 1>) 2 LOAD_CONST 1 ('<listcomp>') 4 MAKE_FUNCTION 0 6 LOAD_CONST 2 (()) 8 GET_ITER 10 CALL_FUNCTION 1 12 RETURN_VALUE Disassembly of <code object <listcomp> at 0x7fea68e0dc60, file "<dis>", line 1>: 1 0 BUILD_LIST 0 2 LOAD_FAST 0 (.0) >> 4 FOR_ITER 4 (to 14) 6 STORE_FAST 1 (_) 8 LOAD_CONST 0 (True) 10 LIST_APPEND 2 12 JUMP_ABSOLUTE 2 (to 4) >> 14 RETURN_VALUE
观察到列表推导式会创建一个名为<listcomp>的代码对象,封装迭代和列表构建逻辑,随后立即调用该函数。疑问是:这是一种优化手段吗?
回答
这不是优化手段,核心原因有两个:
1. 作用域隔离
Python 3之前的列表推导式存在作用域污染问题——循环变量(比如例子里的_)会泄漏到外层作用域中。比如在Python 2里执行[x for x in range(3)]后,外层的x变量会被设置为2。
Python 3为了修复这个问题,把列表推导式的逻辑封装成独立的嵌套函数(也就是你看到的<listcomp>代码对象)。这样循环变量就被限制在函数的局部作用域内,不会影响外层的变量环境,彻底解决了作用域泄漏问题。
2. 实现简洁性
从CPython的底层实现角度,复用现有的函数调用机制来处理推导式逻辑,比专门为列表推导式设计一套全新的字节码流程更高效。而且生成器表达式、集合推导式、字典推导式都是采用类似的函数封装方式,统一的实现逻辑减少了代码重复,降低了维护成本。
你看到的字节码流程就是:加载预编译好的<listcomp>代码对象→将其转换为函数→传入迭代对象(空元组())→函数内部执行循环、构建列表并返回结果。
内容的提问来源于stack exchange,提问作者Amir reza Riahi
相关产品推荐
相关产品推荐

