Python中的不等式和括号

4

因此,在Python中,可以轻松检查真实条件,并使用括号优先处理真实条件的顺序,例如:

>>> 3 > 2
True
>>> (3 > 2) is True
True

但是这些到底意味着什么,我无法理解它们为什么返回False/True:

>>> 3 > 2 is True
False
>>> 3 > (2 is True)
True
>>> 5 < 3 is False > 2 is True
False
>>> 5 < 3 is False is True > 2 is True
False
>>> 3 < 5 is True is True > 2 is True
False
>>> 3 < 5 is True is True > 2 is True is not False is True
False
>>> 3 < 5 is True is (True > 2 is True is not False) is True
False
>>> 3 < 5 is True is (True > (2 is True) is not False) is True
False
>>> (3 < 5 is True is True) > 2 is (True is not False is True)
False

我知道这些条件不是Pythonic的,但我应该如何理解它们?它仍然是从左到右吗?
还是is True和/或is False更重要?

我觉得这个问题是在写双重不等式时运算符优先级是什么的重复。但是,我会让你来决定。否则,请将评论留作附加信息。 - Trenton McKinney
3个回答

3
您可以使用dis模块分析每个案例,以找出确切的情况。例如:
In [1]: import dis
In [2]: def test():
   ...:     return 3 > 2 is True
   ...: 
In [3]: dis.dis(test)
  2           0 LOAD_CONST               1 (3)
              3 LOAD_CONST               2 (2)
              6 DUP_TOP             
              7 ROT_THREE           
              8 COMPARE_OP               4 (>)
             11 JUMP_IF_FALSE_OR_POP    21
             14 LOAD_GLOBAL              0 (True)
             17 COMPARE_OP               8 (is)
             20 RETURN_VALUE        
        >>   21 ROT_TWO             
             22 POP_TOP             
             23 RETURN_VALUE

每一步操作后,栈的状态如下:

 0: 3
 3: 3 2
 6: 3 2 2
 7: 2 3 2
 8: 2 True
11: 2
14: 2 True
17: False (comparison was: "2 is True")
20: (False is returned)

在我看来,这似乎是Python中的一个bug。也许有一些好的解释为什么会发生这种情况,但我建议上报给开发者。

简单来说,这段代码的作用是:

if 3 > 2:
    if 2 is True:
        return True
return False

编辑:也许它实际上有一些奇怪的意义。考虑如何检查链接的不等式:

3 > 2 > 1  ==  3 > 2 and 2 > 1

如果它可以推广到:

x op1 y op2 z == x op1 y and y op2 z

这可以解释结果。

编辑2:实际上与文档匹配。请查看链接比较:https://docs.python.org/2/reference/expressions.html#not-in

comparison    ::=  or_expr ( comp_operator or_expr )*
comp_operator ::=  "<" | ">" | "==" | ">=" | "<=" | "<>" | "!="
                   | "is" ["not"] | ["not"] "in"

is 被认为是一种与 > 相同的好比较方式,因此将应用多重比较的标准扩展。

其他比较现在应该很清楚了。唯一需要注意的奇怪新细节是:True == 1False == 0,所以在 3 > (2 is True)3 > False。大多数其他内容可以通过扩展来解释。例如:

5  <     3     is       False       >     2     is True  == False
(5 < 3) and (3 is False) and (False > 2) and (2 is True) == False

只是想知道,“JUMP_IF_FALSE_OR_POP”操作应该表示什么? - R Nar
字面上讲,如果栈顶为 false 就跳转,否则弹出该值。 - viraptor
抱歉,我应该更具体一些:JUMP是什么意思? - R Nar
1
这意味着堆栈不受影响,并且程序从引用标签开始执行。在这里,它是 JUMP_IF_FALSE_OR_POP 21,因此如果堆栈顶部是“False”,则下一个执行的字节码将是 21 ROT_TWO - viraptor
谢谢@viraptor,现在开始有点明白了,但是在没有清晰的头脑的情况下,仍然有点难以理解这些条件 =) - alvas

2
在Python中,Boolean类型是int的一个子类型。因此,True实际上是1,而False是0。
Python中的所有比较操作具有相同的优先级(><>=<===!=is [not][not] in)。
引用如下:

比较可以任意链接,例如,x < y <= z等价于x < y and y <= z,但当发现x < y为false时,z在两种情况下都不会被评估。

形式上,如果abc,...,yz是表达式,op1op2,...,opN是比较运算符,则a op1 b op2 c ... y opN z等价于a op1 b and b op2 c and ... y opN z,但每个表达式最多只被评估一次。

请参见Python语言参考

但是只有通过值之间的比较 1True 才能得到正确的结果。 因此,True is 11 is True 是 False。而 True == 11 == True 则为 True。 - alvas
是的,True11.0都是不同类型的对象,但它们具有相同的值。因此,对象身份运算符is始终会指出它们是不同的。其他比较运算符将始终比较它们的值。 - user2683246

1

首先,您可能需要一个小作弊表来了解评估顺序。这些运算符中的大多数都在同一个括号上,因此从左到右进行评估。有了这个知识,这些示例就可以被翻译成它们的“真实”含义:

(3 < 5 is True is True) > 2 is (True is not False is True)

等价于:(实际上并不存在 __is____not__,因为这些关键字不能被重载。这只是为了举例说明)

(3.__lt__(5).__is__(True).__is__(True)).__gt__(2).__is__(True.__is__(False).__not__().__is__(True))

我可能省略了一些在这里描述的细节。好的一点是,你(希望)永远不会写出如此复杂的表达式,以至于需要查阅文档才能知道它的作用。

编辑:算了,这种比较方式行不通。比较是“成对全部比较”的,就像viraptor的答案中描述的那样。


1
这实际上是不正确的。看看我的回应。仅使用比较的表达式被特殊处理。您引用的页面说:“(除了比较,包括测试,它们都具有相同的优先级并从左到右链接 - 请参见比较部分 - 和指数,它从右到左分组)”。此外,“is not”是字节码中的一个运算符(无论您是写not 1 is 2还是1 is not 2)。 - viraptor
我意识到这些不准确之处,但我认为为了说明问题,让它们滑过去应该没问题。毕竟这是文档中的一个完整章节,有其存在的理由。 - Felk
1
我的意思是(3 < 5 is True)并不等同于3.__lt__(5).__is__(True)。实际上应为(3.__lt__(5)) and (5.__is__(True)) - viraptor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接