bigywater.tech
新版本特性 · 2

SyntaxError: iterable unpacking cannot be used in comprehension:Python 3.15 里 [*a for a in xs] 合法了,和嵌套推导式、chain、extend 的速度实测

“SyntaxError: iterable unpacking cannot be used in comprehension” 是 Python 3.14 及以前写 [*a for a in xs] 时的报错,3.15 起这个写法终于合法了。这篇在本机用 3.14.9 和 3.15.0 并排跑,看四种推导式的行为、写错时的报错文本、字节码,以及和 chain.from_iterable、extend 循环、嵌套推导式、sum 比拍平速度。

4 种
3.15 里推导式的元素位置可以写 * 或 ** 的形式:列表、集合、字典、生成器表达式(3.14 全部是 SyntaxError)
0.028 ms
1000 个子列表×10 个元素拍平:[*a for a in xs] 对嵌套推导式的 0.065 ms(3.15)
LIST_EXTEND
星号写法的字节码:每个子序列一条 LIST_EXTEND,没有内层循环

语法

实测 · 本机执行输出
  Python 3.14(退出码 0):
      列表推导 [*a for a in xs]              -> SyntaxError: iterable unpacking cannot be used in comprehension
      集合推导 {*a for a in xs}              -> SyntaxError: iterable unpacking cannot be used in comprehension
      字典推导 {**d for d in ds}             -> SyntaxError: dict unpacking cannot be used in dict comprehension
      生成器表达式 (*a for a in xs)            -> SyntaxError: iterable unpacking cannot be used in comprehension
  Python 3.15(退出码 0):
      列表推导 [*a for a in xs]              -> [1, 2, 3, 4, 5, 6]
      集合推导 {*a for a in xs}              -> {1, 2, 3, 4, 5, 6}
      字典推导 {**d for d in ds}             -> {'a': 1, 'b': 3, 'c': 4}
      生成器表达式 (*a for a in xs)            -> generator -> [1, 2, 3, 4, 5, 6]

3.14 里四种推导式的元素位置写 * 或 ** 都是 SyntaxError;3.15 里都能写,字典推导里 {**d for d in ds} 是把每个字典合并。

语义

实测 · 本机执行输出
  Python 3.15(退出码 0):
      字典推导,b 在两个字典里都有: {'a': 1, 'b': 3, 'c': 4}
      带 if: [1, 2, 3, 4, 5, 6]
      两个 for: [1, 2, 1, 2, 3, 3, 4, 5, 6, 4, 5, 6]
      嵌套的生成器作为被解包对象: [10, 20, 30, 40, 50, 60]
      生成器表达式只取第 1 个元素: 1 | 此时 src 已经产出了 1 个子序列
      取完之后 src 产出了 4 个子序列,剩下的元素: [2, 3, 4, 5, 6]

重复键后面的覆盖前面的;if 和多个 for 照常;生成器表达式仍然惰性。

报错文本

实测 · 本机执行输出
  Python 3.15(退出码 0):
      [*a, 0 for a in xs]        -> SyntaxError: did you forget parentheses around the comprehension target?
      [*5 for a in xs]           -> TypeError: Value after * must be an iterable, not int
      [*a for a in [1, 2]]       -> TypeError: Value after * must be an iterable, not int
      {**d for d in [1, 2]}      -> TypeError: 'int' object is not a mapping
      {**d for d in [[1, 2]]}    -> TypeError: 'list' object is not a mapping
      {**d: 1 for d in ds}       -> SyntaxError: cannot use dict unpacking in a dictionary key
      {*a: 1 for a in xs}        -> SyntaxError: cannot use a starred expression in a dictionary key
      dict(**d for d in ds)      -> SyntaxError: cannot use dict unpacking in generator expression

多写元素是编译期 SyntaxError;被解包的不是可迭代对象或映射是运行时 TypeError;key 位置不能用 ** 或 *。

字节码

实测 · 本机执行输出
  3.15 星号写法(退出码 0):
      3.15 [*a for a in xs]: {'FOR_ITER': 1, 'LIST_EXTEND': 1}
  3.15 嵌套写法(退出码 0):
      3.15 [x for a in xs for x in a]: {'FOR_ITER': 2, 'LIST_APPEND': 1}
  3.14 嵌套写法(退出码 0):
      3.14 [x for a in xs for x in a]: {'FOR_ITER': 2, 'LIST_APPEND': 1}

星号写法没有内层循环,每个子序列一条 LIST_EXTEND;嵌套写法每个元素一条 LIST_APPEND。

速度

实测 · 本机执行输出
  1000 个子列表×10 个元素(ms/次):
      写法                                    3.14      3.15
      [x for a in xs for x in a]           0.076     0.065
      list(chain.from_iterable(xs))        0.062     0.061
      for 循环 r.extend(a)                   0.034     0.034
      sum(xs, [])                          6.203     6.178
      [*a for a in xs]                      语法错误     0.028
  100000 个子列表×1 个元素(ms/次):
      写法                                    3.14      3.15
      [x for a in xs for x in a]           2.189     1.274
      list(chain.from_iterable(xs))        1.656     1.647
      for 循环 r.extend(a)                   1.528     1.640
      sum(xs, [])                                  (没跑,太慢)
      [*a for a in xs]                      语法错误     1.080
  10 个子列表×100000 个元素(ms/次):
      写法                                    3.14      3.15
      [x for a in xs for x in a]           7.624     6.894
      list(chain.from_iterable(xs))        6.897     5.820
      for 循环 r.extend(a)                   3.901     3.146
      sum(xs, [])                         11.123    10.919
      [*a for a in xs]                      语法错误     2.944

三种形状下星号写法都最快;sum(xs, []) 是平方级。嵌套推导式本身在 3.15 上比 3.14 更快的幅度取决于形状。

分步演示

推导式里的 * 解包实测
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Homebrew 的 Python 3.14.9 与 3.15.0(同一台机器上两个解释器并排跑同一份代码;两者都不是自由线程构建,也都没有启用 JIT);每个例子是临时目录里的独立小脚本,用子进程运行并取真实的 stdout / stderr(路径换成 );计时用 time.perf_counter,数字每次运行会有小幅抖动。本篇语法与报错文本用 eval / compile 在两个解释器上各跑一遍;速度用 timeit,每个组合先估计次数再取 7 次重复里的最小值(ms/次)
    • 没有验证:嵌套推导式在 3.15 上比 3.14 更快的原因(只量到了结果,没有查原因);更大的数据量、其他元素类型(字符串、元组)下的速度;内存占用;PyPy 等其他实现;类型检查器对新语法的支持;PEP 798 的完整规范(本篇只验证了行为);异步推导式里的 * 解包
    京ICP备2026067502号-1京公网安备11010502063487号