10
A = 314

if A == A == A:
    print('True #1')

if A == A == 271:
    print('True #2')

lie = 0
if lie is lie is lie:
    print('no matter how white, how small,')
    print('how incorporating of a smidgeon')
    print('of truth there be in it.')

Result:

True #1
no matter how white, how small,
how incorporating of a smidgeon
of truth there be in it.

I know it is not normal to use two "="s and "is"s in the if sentence. But I would like to know how the Python interpreter intereprets the if statement.

Is the expression lie is lie is lie interpreted simultaneously, or short-circuit way?

NoDataDumpNoContribution
  • 10,591
  • 9
  • 64
  • 104
sevenOfNine
  • 1,509
  • 16
  • 37
  • 2
    What do you mean by "simultaneously"? I'm guessing it's being interpreted like `0 < x < 3` just with different operators (and operands). – tripleee Jan 18 '18 at 07:26
  • 2
    Interesting question, but almost certainly a dupe, operator chaining must have been asked before on SO. – user202729 Jan 18 '18 at 07:30
  • @tripleee By non "simultaneously", I mean "lie is lie" return "True", then "True is lie", whichi may fail. According to replies, I understand that it is interpreted as "lie is lie and lie is lie". – sevenOfNine Jan 18 '18 at 07:39

3 Answers3

14

What you've happened across is called operator chaining.

From the documentation on Comparisons:

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).

Emphasis mine.

So, this would mean lie is lie is lie is interpreted as (lie is lie) and (lie is lie), and nothing more.

More generally, a op b op c op d ... is evaluated the same as a op b and b op c and c op d ... and so on. The expression is parsed according to python's grammar rules. In particular;

comparison    ::=  or_expr ( comp_operator or_expr )*
comp_operator ::=  "<" | ">" | "==" | ">=" | "<=" | "!="
                   | "is" ["not"] | ["not"] "in"
cs95
  • 379,657
  • 97
  • 704
  • 746
7

This question has many answers already, but consider the function split into bytecode:

def f():
    lie = 0
    if lie is lie is lie:
        print('Lie')

dis.dis(f)

  2           0 LOAD_CONST               1 (0)
              2 STORE_FAST               0 (lie)
  3           4 LOAD_FAST                0 (lie)
              6 LOAD_FAST                0 (lie)
              8 DUP_TOP
             10 ROT_THREE
             12 COMPARE_OP               8 (is)
             14 JUMP_IF_FALSE_OR_POP    22
             16 LOAD_FAST                0 (lie)
             18 COMPARE_OP               8 (is)
             20 JUMP_FORWARD             4 (to 26)
        >>   22 ROT_TWO
             24 POP_TOP
        >>   26 POP_JUMP_IF_FALSE       36
  4          28 LOAD_GLOBAL              0 (print)
             30 LOAD_CONST               2 ('Lie')
             32 CALL_FUNCTION            1
             34 POP_TOP
        >>   36 LOAD_CONST               0 (None)
             38 RETURN_VALUE

This suggests that all lies are being checked to see if they match, in a linear fashion. If one fails, it should break/return.

To confirm, consider:

>lie is lie is lie is lie is lie 
True
>lie is not lie is lie is lie is lie is lie
False
>lie is lie is lie is lie is lie is not lie
False
Daniel Lee
  • 7,189
  • 2
  • 26
  • 44
3

It will be interpreted as:

lie = 0
if lie is lie and lie is lie:
    ...
clemens
  • 16,716
  • 11
  • 50
  • 65