Reputation: 1241
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
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.
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
Upvotes: 1
Views: 2199
Reputation: 20689
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 and
Falseis evaluated to
False`.
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.
Upvotes: 1
Reputation: 15872
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.
Upvotes: 1