1

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

3
  • Your question is not clear. Comparison and assignment are two different operations. Comparison doesn't have the same issue as a = b = [1, 2, 3] assignment. Commented Feb 13, 2020 at 12:14
  • I know how to use assgnment. I have no question about that. All I wanna know is whether multiple operation usage is safe in a boolean expression in within a control flow? Commented Feb 13, 2020 at 12:26
  • 1
    @Travis Yes it's safe. You can write multiple boolean expression. Commented Feb 13, 2020 at 12:30

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

Comments

1

From 0 to 8 it compares a < b, at 10 checks if its False, if yes go to 18, rotate stack, pop top value, that is False, because a<b<c is a<b and b<c, so if first value is False, does not need to check the second condition.

But in this case a < b == True, so it continues. At this point as the it has passed the first checkpoint (10) it knows the first condition must have been True so it returns whatever the value is from the b < c condition, which is False, so you get False.

On the contrary, if you check disassembly of 'a

  1           0 LOAD_NAME                0 (a)
              2 LOAD_NAME                1 (b)
              4 COMPARE_OP               0 (<)
              6 JUMP_IF_TRUE_OR_POP     14
              8 LOAD_NAME                1 (b)
             10 LOAD_NAME                2 (c)
             12 COMPARE_OP               0 (<)
        >>   14 RETURN_VALUE

It does the opposite, checks (6) if the first condition is True, if yes, it does not matter what the next condition evaluates to and returns the value, else, returns whatever the next condition evaluates to.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.