Search code examples
pythonif-statementcontrolsboolean-logicboolean-expression

Python use multiple operators in a boolean expression


Background

As we all known, we'd better not assginment several variables use chain assignment like a = b = [1,2,3], because a will be a shalow copy of b. It is not safe because a will change when we revise b.

However, if the initialization is immutable, we can do like this a = b = 1 and it's safe.

Recently, I find a strange usage of multiple operators in the condition expression of a control flow, like if 1 < b < 2: or while a == b == c == 1:

For example, the following control flow excute different chunks under different conditions:

a = 1
b = 1
c = 2

if a == b == c == 1:
    print('All equal!')
else:
    print('At least one variable is not equal to others')

At least one variable is not equal to others


My question

Is this multiple operation usage safe in a boolean expression in within a control flow? I know we should check the operator precedence when we write a boolean expression. Is there anything else we should keep an eye on? I try for a while and I think the multiple operator usage is safe.


Bytecode analysis

I type the bytecode of the following program:

a = 1;b =2;c =1.5
a<b<c
import dis
dis.dis('a<b<c')
  1           0 LOAD_NAME                0 (a)
              2 LOAD_NAME                1 (b)
              4 DUP_TOP
              6 ROT_THREE
              8 COMPARE_OP               0 (<)
             10 JUMP_IF_FALSE_OR_POP    18
             12 LOAD_NAME                2 (c)
             14 COMPARE_OP               0 (<)
             16 RETURN_VALUE
>   18 ROT_TWO
             20 POP_TOP
             22 RETURN_VALUE```

I can only recognize that it compare a and b at step 10 and then compare a and c at step 14. But why it still return False. I not familiar with analysing bytecode. If someone can help with analysing it, I will be very appreciated! Here is an official guide of Module: dis


Solution

  • This is the code given by you.

    a = 1
    b = 1
    c = 2
    
    if a == b == c == 1:
        print('All equal!')
    else:
        print('At least one variable is not equal to others')
    

    Let's understand what it means.a==b==c==1 is evaluated to True only when all three of them are equal to 1. Else evaluated to False. a==b==c is evaluated as a==b and b==c and c==a.

    To get what you wanted you have to do this.

    if a==b==c==1:
        print('All are equal')
    elif (a==b) or (b==c) or (c==a):
       print('At least one variable is not equal to others')
    else:
        print('none of them are equal')
    

    Now for analysis the second you provided with bytcode.

    a = 1;b =2;c =1.5
    a<b<c
    

    a<b<c is evaluated as a<b and b<c in your case this is 1<2 and 2<1.5 which is evaluated to False. 1<2 is evaluated to True and 2<1.5 is evaluated to False. True andFalseis evaluated toFalse`.

    Byte code:

    In [2]: a=1;b=2;c=1.5
    
    In [3]: dis.dis('a<b and b<c')
      1           0 LOAD_NAME                0 (a)
                  2 LOAD_NAME                1 (b)
                  4 COMPARE_OP               0 (<)
                  6 JUMP_IF_FALSE_OR_POP    14
                  8 LOAD_NAME                1 (b)
                 10 LOAD_NAME                2 (c)
                 12 COMPARE_OP               0 (<)
            >>   14 RETURN_VALUE
    

    6 JUMP_IF_FALSE_OR_POP 14 What this line tells us is jump to line 14 if false. In logical and False and any_bool_value always evaluates to False.

    Now if 6 JUMP_IF_FALSE_OR_POP 14 is True then it continues executing 8 to 14.

    And it's safe to use Multiple boolean operators in a single expression.