Python `or`、`and` 运算符优先级示例
Python `or`, `and` operator precedence example
我无法在 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 "yay\nTrue"
对于 4 种可能性中的每一种,当 or
之前的表达式是 True
时,它是唯一被评估的表达式。如果运算符优先级有效,这应该打印 "nay\nnope\nyay\nTrue"
或 "nay\nyay\nTrue"
,并短路,因为 and
应该被评估为第一个。
从这个例子中想到的是 Python 从左到右读取布尔表达式,并在结果已知时结束它,而不考虑运算符优先级。
我的错误在哪里或者我遗漏了什么?请举一个例子,其中可见 and
被评估为第一个,而不是由于代码是从左到右解释的。
实际上,您的代码 returns 1
不是因为 or
被评估为第二次,而是因为 1 为真并且不需要进一步评估。这使得行为一致。
您混淆了运算符优先级和求值顺序。
表达式 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()
returns None
这是假的所以我们已经知道 nope()
returns 是什么并不重要(因为它是一个 and
条件第一部分已经 False
) - 所以我们不 运行 它。然后我们 运行 yay()
因为它可以更改表达式的已经 False
的值 - returns True
.
or
的优先级低于 and
,因此 a or b and c
被解释为 a or (b and c)
.
此外,逻辑运算符被计算为"lazily",因此如果a
为True
,a or b
将不会导致b
的计算。
Python 从左到右计算表达式,并在知道结果后立即停止。
例如,在 or 运算符的情况下,如果左侧的实体为 True,则可以肯定该运算符 return 为真,在这种情况下不会评估右侧的表达式。
在and
运算符的情况下,如果左边的表达式为False,则运算符肯定应该returnFalse。所以这里不计算右边的表达式。
这就是您的示例中发生的情况。
我无法在 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 "yay\nTrue"
对于 4 种可能性中的每一种,当 or
之前的表达式是 True
时,它是唯一被评估的表达式。如果运算符优先级有效,这应该打印 "nay\nnope\nyay\nTrue"
或 "nay\nyay\nTrue"
,并短路,因为 and
应该被评估为第一个。
从这个例子中想到的是 Python 从左到右读取布尔表达式,并在结果已知时结束它,而不考虑运算符优先级。
我的错误在哪里或者我遗漏了什么?请举一个例子,其中可见 and
被评估为第一个,而不是由于代码是从左到右解释的。
实际上,您的代码 returns 1
不是因为 or
被评估为第二次,而是因为 1 为真并且不需要进一步评估。这使得行为一致。
您混淆了运算符优先级和求值顺序。
表达式 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()
returns None
这是假的所以我们已经知道 nope()
returns 是什么并不重要(因为它是一个 and
条件第一部分已经 False
) - 所以我们不 运行 它。然后我们 运行 yay()
因为它可以更改表达式的已经 False
的值 - returns True
.
or
的优先级低于 and
,因此 a or b and c
被解释为 a or (b and c)
.
此外,逻辑运算符被计算为"lazily",因此如果a
为True
,a or b
将不会导致b
的计算。
Python 从左到右计算表达式,并在知道结果后立即停止。 例如,在 or 运算符的情况下,如果左侧的实体为 True,则可以肯定该运算符 return 为真,在这种情况下不会评估右侧的表达式。
在and
运算符的情况下,如果左边的表达式为False,则运算符肯定应该returnFalse。所以这里不计算右边的表达式。
这就是您的示例中发生的情况。