为什么表达式0< 0 == 0在Python中返回False?

时间:2011-05-20 15:19:09

标签: python

在Python 2.6中查看Queue.py,我发现这个构造我觉得有点奇怪:

def full(self):
    """Return True if the queue is full, False otherwise
    (not reliable!)."""
    self.mutex.acquire()
    n = 0 < self.maxsize == self._qsize()
    self.mutex.release()
    return n

如果maxsize为0,则队列永远不会满。

我的问题是这个案例是如何运作的? 0 < 0 == 0如何被视为错误?

>>> 0 < 0 == 0
False
>>> (0) < (0 == 0)
True
>>> (0 < 0) == 0
True
>>> 0 < (0 == 0)
True

9 个答案:

答案 0 :(得分:110)

我相信Python对关系运算符的序列进行了特殊的处理,使得范围比较易于表达。能说0 < x <= 5而不是说(0 < x) and (x <= 5)要好得多。

这些被称为chained comparisons。这是他们文档的链接。

在你谈到的其他情况下,括号强制一个关系运算符在另一个之前应用,因此它们不再是链式比较。由于TrueFalse的值为整数,因此您可以从括号中获得答案。

答案 1 :(得分:40)

由于

(0 < 0) and (0 == 0)

False。您可以将比较运算符链接在一起,它们会自动扩展到成对比较中。


编辑 - 澄清Python中的真假

在Python中TrueFalse只是bool的实例,它是int的子类。换句话说,True实际上只是1。

这一点是你可以使用与整数完全相同的布尔比较结果。这会导致像

这样令人困惑的事情
>>> (1==1)+(1==1)
2
>>> (2<1)<1
True

但是,只有在对比例进行括号处理以便首先进行评估时才会发生这些情况。否则Python将扩展比较运算符。

答案 2 :(得分:18)

你经历的奇怪行为来自蟒蛇连锁条件的能力。由于它发现0不小于0,因此它决定整个表达式的计算结果为false。一旦你将其分解为单独的条件,你就会改变功能。它最初基本上是对a < b && b == c的原始陈述a < b == c进行测试。

另一个例子:

>>> 1 < 5 < 3
False

>>> (1 < 5) < 3
True

答案 3 :(得分:8)

>>> 0 < 0 == 0
False

这是一个链式比较。如果每个成对比较依次为真,则返回true。它相当于(0 < 0) and (0 == 0)

>>> (0) < (0 == 0)
True

这相当于评估为True的0 < True

>>> (0 < 0) == 0
True

这相当于评估为True的False == 0

>>> 0 < (0 == 0)
True

等同于0 < True,如上所述,评估为True。

答案 4 :(得分:7)

查看反汇编(字节代码)很明显为什么0 < 0 == 0False

以下是对此表达式的分析:

>>>import dis

>>>def f():
...    0 < 0 == 0

>>>dis.dis(f)
  2      0 LOAD_CONST               1 (0)
         3 LOAD_CONST               1 (0)
         6 DUP_TOP
         7 ROT_THREE
         8 COMPARE_OP               0 (<)
        11 JUMP_IF_FALSE_OR_POP    23
        14 LOAD_CONST               1 (0)
        17 COMPARE_OP               2 (==)
        20 JUMP_FORWARD             2 (to 25)
   >>   23 ROT_TWO
        24 POP_TOP
   >>   25 POP_TOP
        26 LOAD_CONST               0 (None)
        29 RETURN_VALUE

注意第0-8行:这些行检查0 < 0是否显然将False返回到python堆栈。

现在注意第11行:JUMP_IF_FALSE_OR_POP 23 这意味着如果0 < 0返回False,请执行跳转到第23行。

现在,0 < 0False,因此会跳转,从而为堆栈留下False,这是整个表达式0 < 0 == 0的返回值,甚至虽然== 0部分甚至没有被检查过。

因此,总而言之,答案就像在这个问题的其他答案中所说的那样。 0 < 0 == 0具有特殊含义。编译器将其评估为两个术语:0 < 00 == 0。与它们之间有and的任何复杂布尔表达式一样,如果第一个失败,则第二个也不会被检查。

希望这会对事情有所启发,我真的希望我用来分析这种意外行为的方法将鼓励其他人在将来尝试相同的事情。

答案 5 :(得分:2)

也许docs的摘录可以提供帮助:

  

这些就是所谓的“富人”   比较“方法,并被称为   用于优先比较运算符   至__cmp__()以下。通信   运算符符号和方法之间   名称如下:x<y次呼叫   x.__lt__(y)x<=y来电x.__le__(y),   x==y来电x.__eq__(y)x!=yx<>y   致电x.__ne__(y)x>y来电   x.__gt__(y)x>=y来电。x.__ge__(y)   NotImplemented

     

丰富的比较方法可能会返回   单身False如果是的话   没有实现a的操作   给出一对论点。通过   约定,Truebool()是   返回进行成功比较。   但是,这些方法可以返回任何方法   值,所以如果是比较运算符   用于布尔上下文(例如,在   if语句的条件),   Python会在值上调用x==y   确定结果是否为真或   假的。

     

没有隐含的关系   在比较运算符中。该   x!=y的真相并不意味着__eq__()   是假的。因此,在定义时   __ne__(),还应定义__hash__(),以便运算符按预期运行。见段落   在__lt__()处获取一些重要说明   在创建可用的对象   支持自定义比较操作   并可用作字典键。

     

没有swapped-argument版本   这些方法(将在使用时使用)   左参数不支持   操作但正确的论点   做);相反,__gt__()__le__()   是彼此的反思,__ge__()   和__eq__()是彼此的   反思,__ne__()x < y <= z   是他们自己的反思。

     

丰富比较方法的论据   永远不会被胁迫。

这些是比较,但由于你是chaining comparisons,你应该知道:

  

比较可以链接   任意地,例如,x < y and y <= z是   相当于{{1}},除了   y只评估一次(但在   两个案例z都没有被评估   当x < y被发现是假的。)

     

形式上,如果a,b,c,...,y,z是   表达式和op1,op2,...,opN是   比较运算符,然后是op1 b op2   c ... y opN z相当于op1 b   和b op2 c和... y opN z,除了   每个表达式都在   最多一次。

答案 6 :(得分:2)

正如其他人提到的x comparison_operator y comparison_operator z(x comparison_operator y) and (y comparison_operator z)的语法糖,其奖励是y只评估一次。

因此,您的表达式0 < 0 == 0确实是(0 < 0) and (0 == 0),其评估结果为False and True,仅为False

答案 7 :(得分:1)

这就是它的荣耀。

>>> class showme(object):
...   def __init__(self, name, value):
...     self.name, self.value = name, value
...   def __repr__(self):
...     return "<showme %s:%s>" % (self.name, self.value)
...   def __cmp__(self, other):
...     print "cmp(%r, %r)" % (self, other)
...     if type(other) == showme:
...       return cmp(self.value, other.value)
...     else:
...       return cmp(self.value, other)
... 
>>> showme(1,0) < showme(2,0) == showme(3,0)
cmp(<showme 1:0>, <showme 2:0>)
False
>>> (showme(1,0) < showme(2,0)) == showme(3,0)
cmp(<showme 1:0>, <showme 2:0>)
cmp(<showme 3:0>, False)
True
>>> showme(1,0) < (showme(2,0) == showme(3,0))
cmp(<showme 2:0>, <showme 3:0>)
cmp(<showme 1:0>, True)
True
>>> 

答案 8 :(得分:0)

我认为Python在魔术之间做的很奇怪。与1 < 2 < 3相同意味着2介于1和3之间。

在这种情况下,我认为它正在[中间0]大于[左0]并且等于[右0]。中间0不大于左0,因此它的计算结果为假。