itertools.chain(nested)最省内存,因其返回生成器、逐个yield元素;需解包避免TypeError,仅适用于纯二维结构。

用 itertools.chain 扁平化二维列表最省内存
如果嵌套列表很大,又不想一次性把所有元素加载到内存里(比如处理上万行 CSV 数据后的嵌套结构),itertools.chain 是更轻量的选择。它返回的是迭代器,不是新列表。
常见错误是直接写 list(itertools.chain(nested_list)) —— 这会把整个二维列表当做一个元素传进去,报错 TypeError: chain expected at most 1 arguments, got 2。
正确做法是解包:
import itertools nested = [[1, 2], [3, 4, 5], [6]] flattened = list(itertools.chain(*nested)) # → [1, 2, 3, 4, 5, 6]
- 必须加
*解包,否则传的是单个 list 对象 - 只适用于「纯二维」,即每个子项都是 list/tuple;含字符串、数字会触发
TypeError - 性能上比列表推导式略快,尤其在大嵌套时,因为不涉及 Python 层面的循环逻辑
列表推导式更直观,但要注意括号顺序
二维扁平化用列表推导式最常见,但新手常把内外层顺序写反,结果得到和原结构一样的嵌套。
立即学习“Python免费学习笔记(深入)”;
错误写法:[item for item in sublist for sublist in nested] —— 这会先遍历 sublist,但此时 sublist 还没定义,直接报 NameError。
正确顺序是「外层迭代在前,内层在后」:
nested = [[1, 2], [3, 4, 5], [6]] flattened = [item for sublist in nested for item in sublist]
- 记住口诀:「for 外层 in 大容器,for 内层 in 外层」
- 支持任意可迭代子项(tuple、range、甚至生成器),比
chain更灵活 - 如果子项里有字符串,比如
[['a', 'b'], ['c']],会把字符串当可迭代对象拆成字符 →['a','b','c'],这可能不是你想要的
遇到非二维结构(如含 None、int 或三层嵌套)怎么办
itertools.chain 和基础列表推导式都只处理严格二维。一旦出现 [1, [2, 3], [4]] 或 [[[1,2]]],两者都会出错或结果异常。
这时不能硬套,得加判断:
def flatten_2d_safe(lst):
result = []
for item in lst:
if isinstance(item, (list, tuple)):
result.extend(item)
else:
result.append(item)
return result
<p>flatten_2d_safe([1, [2, 3], [4]]) # → [1, 2, 3, 4]- 别用
isinstance(item, list)单独判断,漏掉tuple或range - 避免递归调用(如通用 flatten 函数),除非明确需要处理任意深度;二维场景下递归是过度设计,也慢
- 如果数据来自 JSON 或外部 API,先用
print(type(x), x)看两眼再选方案
为什么不用 sum(nested, [])
有人用 sum(nested, []) 扁平化,看起来很短,但这是个隐藏陷阱。
它本质是不断做 [] + sublist1 + sublist2 + ...,每次 + 都新建 list,时间复杂度 O(n²),嵌套越长越慢。1000 个子列表时,比 chain 慢 10 倍以上。
- 仅适合玩具数据或临时调试,别放进生产代码
- 如果子列表里有字符串,
sum会尝试[] + 'abc',直接TypeError - 语义不清:
sum本意是求和,用它做扁平化会让后续维护者多花三秒反应
真正要快,就用 itertools.chain;要清晰易读,就用列表推导式。混用或硬凑奇技淫巧,最后都在 debug 里还债。


















