Python中any/all传一次性可迭代对象选列表还是元组更优
先纠正一个核心认知偏差
你写的圆括号版本根本不是元组写法——Python从来没有元组推导式这个语法,圆括号里包的for循环表达式是生成器表达式,属于惰性迭代器的一种。真要构造元组得显式写tuple("city" in location for location in locations),会把所有结果算完再打包成元组,和你现在写的括号版本逻辑天差地别,性能表现也完全不一样。
两个维度的性能对比
内存占用
- 列表推导式写法:会一次性在内存里构造完整的临时列表,把所有迭代产生的布尔值全存下来,内存占用和待遍历的数据量正相关,属于O(n)级别。如果待遍历的序列有几十万、上百万条元素,这个临时列表会吃掉非常可观的内存。
- 你示例中的括号(生成器)写法:走的是惰性计算逻辑,不会提前生成任何结果,迭代到哪个元素才算哪个元素的布尔值,全程只存生成器的运行状态,不存全量计算结果,内存占用是恒定的O(1)级别,和待遍历的数据集大小完全无关,内存优势是碾压级的。
- 补充:如果是显式构造的真实元组,因为是不可变结构,内存开销比同内容的列表低10%~20%左右,但本质还是要存全量元素,内存占用依然是O(n)级别,和生成器的优势完全不在一个量级。
执行时间
执行速度没有绝对的优劣,完全取决于场景:
- 能触发短路逻辑的场景:也就是遍历到靠前位置的元素就能拿到最终结果——比如
any()碰到第一个真值、all()碰到第一个假值,生成器写法的速度会远快于列表/元组写法。因为生成器碰到短路条件会立刻停止计算,后面的元素根本不会处理;而列表/元组写法必须先跑完整个循环、构造完完整的临时序列,才会把结果传给any()/all(),平白做了大量无用功。如果待遍历的数据集很大、匹配项又很靠前,两者的速度差可以达到成千上万倍。 - 必须遍历完所有元素才能出结果的场景:比如
any()场景下所有元素都不匹配,得全部遍历完才能返回False,这时候列表/元组版本的速度可能略快于生成器——因为生成器每次迭代都有调度开销,而列表/元组是连续内存结构,底层遍历效率稍高,但这个差距通常在5%以内,绝大多数业务场景根本感知不到。
编码建议
给any()、all()这类自带短路逻辑的内置函数传参时,直接传生成器表达式是最优选择,甚至可以省略生成器外层的括号,代码更简洁:
locations = ["foo", "bar", "baz"] if any("city" in location for location in locations): print("Locations includes a city")
内容的提问来源于stack exchange,提问作者Neil
相关产品推荐
相关产品推荐

