alvas
alvas

Reputation: 122022

Inequalities and Parenthesis in Python

So in python, truth conditions can be easily checked and with parenthesis it prioritize the order of true conditions, e.g. these are easy to understand:

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

But what does these mean, I couldn't grasp the logic of why they return 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

I know these are not pythonic conditions but how should I understand them? Is it still from left to right?

Or does is True or/and is False takes presidence?

Upvotes: 4

Views: 1148

Answers (3)

Felk
Felk

Reputation: 8224

First off, you propably need a little cheat sheet to know the order of evaluation. Most of these operators are on the same bracket and are therefore evaluated left-to-right. With this knowledge, the examples can be translated to their "real" meaning:

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

is equivalent to: (there actually are no __is__ and __not__, because those are keywords that cannot be overloaded. It's for illustration purposes)

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

I might spared out some details that are described here. The good thing is that you (hopefully) never write such complicated expressions that you need to check the documentation to know what it does.

EDIT: Nevermind, it doesn't work this way with comparisons. Comparisons get compared "all together pairwise", like described in viraptor's answer.

Upvotes: 1

viraptor
viraptor

Reputation: 34145

You can analyse each of those cases with dis module to figure out exactly what's happening. For example:

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

That means the stack looks like this after each step:

 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)

To me, it looks like a bug in Python to be honest. Maybe there's some good explanation of why this happens, but I'd report it upstream.

Just to rewrite it in equivalent way, the code does:

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

Edit: Maybe it actually makes some weird kind of sense. Consider how checking chained inequalities works:

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

If it generalises to:

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

that would explain the result.

Edit2: This actually matches documentation. Have a look at chained comparisons: https://docs.python.org/2/reference/expressions.html#not-in

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

is is considered just as good comparison as >, so the standard expansion for multiple comparisons is applied.

Other comparisons should be clear now. The only strange new detail needed is: True == 1, False == 0, so 3 > False in 3 > (2 is True). Most others can be explained with the expansions. For example:

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

Upvotes: 3

user2683246
user2683246

Reputation: 3568

Boolean type in python is a subtype of int. So True is actually 1 and False is 0.

All comparison operations in Python have the same priority (>, <, >=, <=, ==, !=, is [not], [not] in).

Comparisons can be chained arbitrarily, e.g., x < y <= z is equivalent to x < 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.

See Python language reference.

Upvotes: 2

Related Questions