>我无法在 Python 中生成示例,该示例显示布尔运算符优先级规则与短路计算相结合。我可以使用以下方法显示运算符优先级:
print(1 or 0 and 0) # Returns 1 because `or` is evaluated 2nd.
但是当我将其更改为此时,短路问题就出现了:
def yay(): print('yay'); return True
def nay(): print('nay')
def nope(): print('nope')
print(yay() or nay() and nope()) # Prints "yaynTrue"
对于 4 种可能性中的每一种,当True
or
之前的表达式时,它是唯一计算的表达式。如果运算符优先级有效,则应打印"naynnopenyaynTrue"
或"naynyaynTrue"
,并带有短路,因为and
应计算第 1 次。
从这个例子中想到的是,Python 从左到右读取布尔表达式,并在结果已知时结束它,而不管运算符优先级如何。
我的错误在哪里或我错过了什么?请举一个例子,其中可以看到and
是第一次计算的,而不是由于代码从左到右解释。
您混淆了运算符优先级和计算顺序。
表达式r = x or y and z
的计算不是tmp = y and z; r = x or tmp
,而是r = x or (y and z)
。此表达式从左到右计算,如果已经决定了or
的结果,则根本不会计算(y and z)
。
请注意,如果or
和and
是函数,则会有所不同;在这种情况下,将在调用函数本身之前计算函数的参数。因此,operator.or_(yay(), operator.and_(nay(), nope()))
打印yay
、nay
和nope
即它打印所有三个,但仍然按从左到右的顺序打印。
您也可以将其推广到其他运算符。由于运算符优先级不同(使用(...)
隐式和显式(,以下两个表达式将产生不同的结果,但两次都从左到右调用函数。
>>> def f(x): print(x); return x
>>> f(1) + f(2) * f(3) / f(4) ** f(5) - f(6) # 1 2 3 4 5 6 -> -4.99
>>> (f(1) + f(2)) * (((f(3) / f(4)) ** f(5)) - f(6)) # 1 2 3 4 5 6 -> -17.29
如评论中所述,虽然操作之间的项是从左到右评估的,但实际操作是根据其优先级进行评估的。
class F:
def __init__(self,x): self.x = x
def __add__(self, other): print(f"add({self},{other})"); return F(self.x+other.x)
def __mul__(self, other): print(f"mul({self},{other})"); return F(self.x*other.x)
def __pow__(self, other): print(f"pow({self},{other})"); return F(self.x**other.x)
def __repr__(self): return str(self.x)
def f(x): print(x); return F(x)
这样,表达式f(1) + f(2) ** f(3) * f(4)
被计算为1
、2
、3
、pow(2,3)
、4
、mul(8,4)
、add(1,32)
,即从左到右计算项(并在堆栈上推送(,表达式在计算参数后立即计算
从yay()
返回的第一个值是True
所以python甚至不会运行表达式的其余部分。这是为了提高效率,因为表达式的其余部分不会影响结果。
以我更改顺序的以下示例为例:
def yay(): print('yay'); return True
def nay(): print('nay')
def nope(): print('nope')
print(nay() and nope() or yay())
输出:
nay
yay
True
这是怎么回事?nay()
返回None
这是伪造的,所以我们已经知道nope()
返回什么并不重要(因为它是一个and
条件,第一部分已经False
了( - 所以我们不运行它。然后我们运行yay()
,因为它可以更改表达式已经False
的值 - 返回True
.
or
的优先级低于and
,因此a or b and c
被解释为a or (b and c)
。
此外,逻辑运算符被"懒惰"地计算,因此如果a
True
,a or b
不会引起b
的计算。
实际上,您的代码返回1
不是因为or
是第二次计算的,而是因为 1 为真,不需要进一步的评估。这使得行为保持一致。
Python 从左到右计算表达式,并在知道结果后立即停止。 例如,在 or 运算符的情况下,如果左侧的实体为 True,那么可以肯定的是,运算符将返回 true,在这种情况下不会计算右侧的表达式。
如果是and
运算符,如果左侧的表达式为 False,则确定运算符应返回 False。因此,此处不计算右侧的表达式。
这就是您的示例中正在发生的事情。