嵌套字典键集合的Python实现:哪种写法最具Python风格?
假设我们有这样一个嵌套字典:
x = {1: {2: 4, 3: 6}, 5: {2:6, 10: 25, 14: 12}}
我们的目标是提取所有内层字典的键,最终得到集合 {2, 3, 10, 14}。下面来聊聊不同实现方式的优劣,以及哪种最符合Python风格。
原始实现代码
首先看最初的实现:
keys = set() for y in x: for z in x[y]: keys.add(z)
这段代码的最大优点是极度直观,哪怕是刚入门的Python开发者也能一眼看懂它的逻辑:遍历外层字典的每个键,再遍历对应内层字典的键,逐个添加到集合中。它的内存效率也不错,不会生成多余的中间数据结构。
尝试过的单行写法及各自不足
作者尝试了几种单行写法,但都有明显缺陷:
itertools.chain解包写法import itertools keys = set(itertools.chain(*x.values()))问题出在
*x.values()的解包操作上:当外层字典包含大量内层字典时,这个操作会把所有内层字典的键一次性展开成一个大的可迭代对象,对于超大型字典来说,会瞬间占用大量内存,导致效率下降。sum拼接列表写法keys = set(sum([x[y].keys() for y in x], []))这种写法的问题更明显:一方面,
sum拼接列表的方式会不断生成新的中间列表,内存开销大;另一方面,代码可读性很差,除非你对sum的这种用法非常熟悉,否则很难快速理解它的意图。集合推导式写法
作者最后参考的写法是:keys = {z for y in x for z in x[y]}
哪种写法最符合Python风格?
如果追求极致可读性,原始的多行循环写法完全没问题,它是最直白的实现方式,维护成本极低。但如果想要兼顾简洁性和Pythonic风格,集合推导式是更好的选择,甚至我们可以把它优化得更易读:
keys = {key for inner_dict in x.values() for key in inner_dict}
这个版本直接遍历外层字典的values()(也就是所有内层字典),再遍历每个内层字典的键,逻辑比之前的推导式更清晰,和原始循环的逻辑完全对应,但只用了一行代码。
它的优势很明显:
- 内存高效:和原始循环一样,是惰性迭代的,不会生成中间大列表,逐个处理元素并添加到集合中。
- 可读性强:熟悉Python推导式的开发者能瞬间理解它的逻辑,变量名
inner_dict和key也比y、z更有语义。 - 地道的Python风格:推导式是Python的特色语法,用它来处理这种“从可迭代对象中收集元素”的场景,既简洁又符合社区的惯用写法。
总的来说,如果你团队的编码风格偏向“清晰优先”,原始循环完全OK;如果追求简洁且不失可读性,优化后的集合推导式是最优解。
内容的提问来源于stack exchange,提问作者Michael come lately

