Python中any()与all()为何未按预期实现短路求值?
all()/any() 短路逻辑"失效"的核心原因
首先明确结论:观察到的现象不是all()/any()没有实现短路,而是混淆了「参数构造阶段的求值」和「函数内部的遍历逻辑」两个完全独立的执行步骤。
Python的函数参数遵循及早求值规则:在函数开始实际执行内部逻辑之前,所有传入的参数都会被先计算出确定值,这个过程和被调用的函数本身没有关系。
第一个测试用例的实际执行流程
第一组测试代码:
def return_true(): print('I have just been printed') return True print(all((False, return_true())))
执行顺序和all()的内部逻辑无关,步骤是:
- 准备传给all()的参数:也就是构造元组
(False, return_true()) - 构造元组需要算出每个位置的具体值:第一个元素是字面量
False可直接得到;第二个元素是return_true()的返回值,必须先执行这个函数才能拿到结果——这一步就会触发print语句,在控制台打印内容,最终元组被构造为确定的(False, True) - 等参数完全准备好,all()才正式开始执行:遍历传入的元组,第一个元素就是False,此时确实触发了短路逻辑,立刻返回False,但此时
return_true()早就执行完毕了,自然能看到打印输出。
第二个测试用例的执行逻辑
第二组any()的测试代码逻辑完全一致:
def return_false(): print('I have just been printed') return False print(any((True, return_false())))
在any()开始执行前,构造元组的阶段就会调用return_false()拿到返回值,完成(True, False)这个元组的构造。等any()正式运行遍历到第一个元素True时,虽然确实触发短路返回了True,但return_false()早就在传参阶段执行完了,所以同样能看到打印内容。
如何看到真正的短路效果
all()/any()的短路逻辑只作用于内部遍历迭代器的阶段:只要迭代器还没产出下一个值,短路触发后就不会继续向后取值。想要观察到符合预期的短路行为,需要用惰性求值的可迭代对象(比如生成器表达式)作为参数,避免元素在传参阶段就被全部计算:
def return_true(): print('I have just been printed') return True # 传入生成器表达式,而非提前构造好的元组/列表 print(all(x for x in (False, return_true())))
运行这段代码会发现控制台不会打印任何来自return_true的输出:因为生成器不会在传参阶段就计算所有元素,all()遍历到第一个False就直接终止,根本不会向生成器请求第二个元素,return_true()从头到尾都不会被调用,这才是短路逻辑的正常表现。
内容的提问来源于stack exchange,提问作者stam
相关产品推荐
相关产品推荐

