在Python中短路all()语句

2 投票
4 回答
771 浏览
提问于 2025-04-17 11:15

有没有办法让Python中的all()语句提前结束?

比如像这样:

return all([x != 0, 10 / x == 2, True, False, 7])

如果x是0的话,这样不会报错吗?

4 个回答

3

这并不会完全按照你想的那样工作,因为Python在把参数传给函数之前,会先计算所有的函数参数。换句话说,它会先把10 / x == 2计算成一个单一的值,然后再调用all。这和Mathematica不一样,Mathematica会直接传递未计算的条件10 / x == 2,这样就能实现你想要的效果。

考虑到你知道要把这个列表传给all,最简单的方法就是利用Python的and运算符的短路特性:

return all([x != 0 and 10 / x == 2, True, False, 7])

另外,你也可以重新写这个数学条件,避免出现除以零的情况,

return all([x != 0, 10 == 2 * x, True, False, 7])

(注意浮点数除法的问题)。

不过,如果你真的想模仿Mathematica的行为,传递一个未计算的条件,我能想到的唯一方法就是传递一个可调用的对象,当你调用它的时候再去计算条件。例如,你可以把列表中的所有元素转换成lambda函数:

return all(f() for f in [lambda: x != 0, lambda: 10 / x == 2,
                     lambda: True, lambda: False, lambda: 7])

如果你不想把所有东西都转换成函数,我想你可以想办法做一个包装器,只调用那些真正可以调用的东西:

return all(f() if callable(f) else f in [x != 0, lambda: 10 / x == 2,
                                                  True, False, 7])

但老实说,这样看起来会很麻烦(除非你是在用Python写一个计算机代数系统 :-P)。

6

如果你的代码是在一个生成器里,那么你也可以用这种方式来快速跳过一些操作:

def test(x):
    yield x != 0
    yield 10/x == 2
    yield True
    yield False
    yield 7

all(test(9))
6

这样做不行,因为在调用all之前,列表(也就是它里面的所有项目)就已经被计算过了。在这种情况下,你最好的选择是像这样:

return x != 0 and 10 / x == 2 and True and False and 7

我假设你已经知道这个,所以我给你提供一个更通用的解决方案,这个方案也适用于列表项不是写死的情况:

return all(f() for f in [lambda: x != 0, lambda: 10 / x == 2, 
                         lambda: True, lambda: False, lambda: 7])

这样的话,表达式只会在短路的all中被计算。

撰写回答