“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 比拍平速度。
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 更快的幅度取决于形状。