问题:为什么表达式0 <0 == 0在Python中返回False?
在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
回答 0
我相信Python对关系运算符的序列有特殊的处理方式,以使范围比较易于表达。可以说更好0 < x <= 5
比好得多(0 < x) and (x <= 5)
。
这些称为链接比较。这是他们文档的链接。
在您谈论的其他情况下,括号会强制在一个关系运算符之前应用一个关系运算符,因此它们不再是链式比较。并且由于True
和的False
值都是整数,因此您可以从括号中得到答案。
回答 1
因为
(0 < 0) and (0 == 0)
是False
。您可以将比较运算符链接在一起,它们会自动扩展为成对比较。
编辑-关于Python中正确与错误的说明
在Python中True
,False
仅仅是的实例bool
,它是的子类int
。换句话说,True
确实只有1。
这样做的目的是,您可以像完全使用整数一样使用布尔比较的结果。这导致诸如
>>> (1==1)+(1==1)
2
>>> (2<1)<1
True
但是,只有在您对比较加括号以使它们首先被评估时,这些情况才会发生。否则,Python将扩展比较运算符。
回答 2
您遇到的奇怪行为来自python链接条件的能力。由于发现0不小于0,因此它决定整个表达式的计算结果为false。一旦将其分解为单独的条件,就在更改功能。最初,它实际上是在测试a < b && b == c
您对的原始声明a < b == c
。
另一个例子:
>>> 1 < 5 < 3
False
>>> (1 < 5) < 3
True
回答 3
>>> 0 < 0 == 0
False
这是一个链式比较。如果每个成对比较依次为true,则返回true。相当于(0 < 0) and (0 == 0)
>>> (0) < (0 == 0)
True
这等效0 < True
于其值为True。
>>> (0 < 0) == 0
True
这等效False == 0
于其值为True。
>>> 0 < (0 == 0)
True
0 < True
如上所述,与之等效的结果为True。
回答 4
查看反汇编(字节码),很明显为什么0 < 0 == 0
是False
。
这是对此表达式的分析:
>>>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 < 0
是False
,因此进行了跳转,即使堆栈中的部分甚至没有被检查,它也会False
为堆栈留下a ,这是整个表达式的返回值。0 < 0 == 0
== 0
因此,总而言之,答案就像对该问题的其他答案中所说的那样。
0 < 0 == 0
有特殊的意义。编译器将其评估为两个术语:0 < 0
和0 == 0
。与任何复杂的布尔表达式一样and
它们之间的一样,如果第一个失败,则甚至不会检查第二个。
希望这对我们有所启发,并且我真的希望我用来分析这种意外行为的方法会鼓励其他人将来尝试相同的方法。
回答 5
正如其他人提到的那样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
。
回答 6
也许从这个摘录文档可以帮助:
这些是所谓的“丰富比较”方法,在
__cmp__()
下面优先于比较运算符。运算符符号和方法名之间的对应关系如下:x<y
呼叫x.__lt__(y)
,x<=y
呼叫x.__le__(y)
,x==y
呼叫x.__eq__(y)
,x!=y
和x<>y
呼叫x.__ne__(y)
,x>y
呼叫x.__gt__(y)
,和x>=y
呼叫x.__ge__(y)
。如果富比较方法
NotImplemented
未实现给定参数对的操作,则可能返回单例。按照惯例,False
并将True
其返回以进行成功比较。但是,这些方法可以返回任何值,因此,如果在布尔上下文中使用比较运算符(例如,在if语句的条件下),Python将调用bool()
该值以确定结果是true还是false。比较运算符之间没有隐含的关系。的真相
x==y
并不意味着那x!=y
是错误的。因此,在定义时__eq__()
,还应该定义一个,__ne__()
以便操作符能够按预期运行。有关__hash__()
创建可哈希对象(支持自定义比较操作并可用作字典键)的一些重要说明,请参见上的段落。这些方法没有交换参数版本(当left参数不支持该操作但right参数支持该操作时使用);相反,
__lt__()
and__gt__()
是彼此的反射,__le__()
and__ge__()
是彼此的反射,and__eq__()
and__ne__()
是自己的反射。丰富比较方法的论点永远不会被强迫。
这些是比较,但是由于要链接比较,因此您应该知道:
可以任意链接比较,例如
x < y <= z
与等效x < y and y <= z
,除了y仅被评估一次(但是在两种情况下,当x <y为假时,z都不被评估)。形式上,如果a,b,c,…,y,z是表达式,而op1,op2,…,opN是比较运算符,则op1 b op2 c … y opN z等效于op1 b和b op2 c和… y opN z,除了每个表达式最多计算一次。
回答 7
这就是它的全部荣耀。
>>> 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
我在想Python在魔术之间做得很奇怪。与1 < 2 < 3
均值2 相同,介于1和3之间。
在这种情况下,我认为它正在执行[中间0]大于[左0]并等于[右0]。中间0不大于左边0,因此它的值为false。