Why does the expression 0 < 0 == 0 return False in Python?
查看python 2.6中的queue.py,我发现这个构造有点奇怪:
1 2 3 4 5 6 7 | 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 |
如果
我的问题是它是如何工作的这个案件?如何认为
1 2 3 4 5 6 7 8 | >>> 0 < 0 == 0 False >>> (0) < (0 == 0) True >>> (0 < 0) == 0 True >>> 0 < (0 == 0) True |
号
我相信python对关系运算符序列有特殊的案例处理,以便于表达范围比较。能说
这些被称为连锁比较。这是他们文档的链接。
对于您所讨论的其他情况,括号强制一个关系运算符先于另一个应用,因此它们不再是链接比较。由于
因为
1 | (0 < 0) and (0 == 0) |
号
是
edit——在python中澄清对错
在python中,
关键是,您可以像使用整数一样使用布尔比较的结果。这会导致混淆
1 2 3 4 | >>> (1==1)+(1==1) 2 >>> (2<1)<1 True |
但是,只有在将比较括起来以便首先对它们进行评估时,才会发生这种情况。否则,python将展开比较运算符。
你所经历的奇怪行为来自于Python的连锁能力。因为它发现0不小于0,所以它决定整个表达式的计算结果为false。一旦你把它分解成不同的条件,你就改变了它的功能。最初基本上是在测试
另一个例子:
1 2 3 4 5 | >>> 1 < 5 < 3 False >>> (1 < 5) < 3 True |
1 2 | >>> 0 < 0 == 0 False |
。
这是一个连锁比较。如果每个成对比较依次为真,则返回真。相当于
1 2 | >>> (0) < (0 == 0) True |
这相当于
1 2 | >>> (0 < 0) == 0 True |
。
这相当于
1 2 | >>> 0 < (0 == 0) True |
。
相当于
从反汇编(字节代码)来看,很明显为什么
下面是对该表达式的分析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | >>>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行:这些行检查
现通知11行:
现在,
所以,最后,答案就像这个问题的其他答案中所说的那样。
希望这能让事情有所启发,我真的希望我用来分析这种意想不到的行为的方法能鼓励其他人在将来尝试同样的方法。
正如其他人提到的,
所以你的表达式
也许从这些文件中摘录可以帮助:
These are the so-called"rich
comparison" methods, and are called
for comparison operators in preference
to__cmp__() below. The correspondence
between operator symbols and method
names is as follows:x calls
x.__lt__(y) ,x<=y callsx.__le__(y) ,
x==y callsx.__eq__(y) ,x!=y andx<>y
callx.__ne__(y) ,x>y calls
x.__gt__(y) , andx>=y calls
x.__ge__(y) .A rich comparison method may return
the singletonNotImplemented if it
does not implement the operation for a
given pair of arguments. By
convention,False andTrue are
returned for a successful comparison.
However, these methods can return any
value, so if the comparison operator
is used in a Boolean context (e.g., in
the condition of an if statement),
Python will callbool() on the value
to determine if the result is true or
false.There are no implied relationships
among the comparison operators. The
truth ofx==y does not imply thatx!=y
is false. Accordingly, when defining
__eq__() , one should also define__ne__() so that the operators will behave as expected. See the paragraph
on__hash__() for some important notes
on creating hashable objects which
support custom comparison operations
and are usable as dictionary keys.There are no swapped-argument versions
of these methods (to be used when the
left argument does not support the
operation but the right argument
does); rather,__lt__() and__gt__()
are each other’s reflection,__le__()
and__ge__() are each other’s
reflection, and__eq__() and__ne__()
are their own reflection.Arguments to rich comparison methods
are never coerced.
号
这些都是比较,但是由于您正在链接比较,您应该知道:
Comparisons can be chained
arbitrarily, e.g.,x < y <= z is
equivalent tox < y and y <= z , except
that y is evaluated only once (but in
both cases z is not evaluated at all
when x < y is found to be false).Formally, if a, b, c, ..., y, z are
expressions and op1, op2, ..., opN are
comparison operators, then a op1 b op2
c ... y opN z is equivalent to a op1 b
and b op2 c and ... y opN z, except
that each expression is evaluated at
most once.
号
就在这里,在它所有的荣耀中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | >>> 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 >>> |
我认为Python在魔法之间做的很奇怪。与
在这种情况下,我认为它所做的是[中间0]大于[左0]等于[右0]。中间0不大于左0,因此计算结果为false。