嵌套列表展平应据结构选择方案:单层用itertools.chain.from_iterable最高效安全;任意深度且需保留字符串等原子值时才用自定义递归;避免sum或numpy因性能与类型问题。

嵌套列表展平不是“选哪个函数更好”的问题,而是“你面对的是什么结构”决定方案——itertools.chain只处理一层嵌套,递归才能应对任意深度。
用 itertools.chain 展平单层嵌套列表(如 [[1,2], [3], [4,5,6]])
这是最常见也最容易误用的场景:看到“嵌套”就下意识想递归,其实多数真实数据(比如 map() 结果、zip() 转列表、分批查询返回值)只是外层一个 list,内层全是 list,没有更深嵌套。
直接用 itertools.chain.from_iterable() 最安全高效:
from itertools import chain <p>nested = [[1, 2], [3], [4, 5, 6]] flattened = list(chain.from_iterable(nested))</p><h1>→ [1, 2, 3, 4, 5, 6]</h1><p>
立即学习“Python免费学习笔记(深入)”;
- 比
[item for sublist in nested for item in sublist]更易读,且不创建中间 list - 不支持非迭代对象(比如混入
None或数字),会报TypeError: 'int' object is not iterable - 如果内层有字符串(如
['ab', 'c']),会被展开成['a','b','c']—— 这是迭代行为,不是 bug
用递归展平任意深度嵌套(含混合类型、字符串不展开)
当你遇到类似 [1, [2, [3, 4]], [[5]], 'hello'] 这种结构,且明确要求字符串当原子值(不拆成字符)、None 或数字要保留原样时,必须自己控制递归逻辑。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
关键判断点不是“有没有嵌套”,而是“当前元素是否为 list(或 tuple)且不应被原子化”:
def flatten(obj):
if isinstance(obj, (list, tuple)):
for item in obj:
yield from flatten(item)
else:
yield obj
<p>mixed = [1, [2, [3, 4]], [[5]], 'hello']
result = list(flatten(mixed))</p><h1>→ [1, 2, 3, 4, 5, 'hello']</h1><p>立即学习“Python免费学习笔记(深入)”;
- 用
yield from避免拼接 list,节省内存 -
isinstance(obj, (list, tuple))比type(obj) == list更健壮,兼容用户自定义序列类 - 如果需要支持
dict的 values 或其他可迭代但非序列类型,得额外加判断,否则会把 dict 当作迭代器展开成 keys
为什么不用 numpy.concatenate 或 sum(lst, [])?
这两个方法看似简洁,但隐患明显:
-
sum(nested, [])依赖 list 的+运算符,时间复杂度是 O(n²),因为每次+都新建 list;嵌套越深、子列表越多,性能越差 -
numpy.concatenate强制所有元素转为同一 dtype,遇到混合类型(如[1, ['a']])会静默转成object数组,后续计算容易出错;且引入 numpy 仅为了展平,过度依赖 - 两者都不处理非 list/tuple 的嵌套(比如 dict 套 list),会直接报错或行为异常
真正麻烦的从来不是“怎么写递归”,而是判断边界:字符串要不要展开、字典怎么处理、生成器要不要立即消费、空值如何保留——这些没统一答案,得看你的数据源头和下游用途。别抄完代码就跑,先 print(type(x), x) 看两眼实际结构。

















