Python is, == operator precedence - python

In Python3,
a = b = 3
a is None == b is None
returns False, but
(a is None) == (b is None)
returns True. So I would assume based on this example alone, == has precedence over is.
However,
a = b = None
a is None == b is None
returns True. And
(a is None) == (b is None)
returns True. But
a is (None == b) is None
returns False. In this case, it would seem as if is has precedence over ==.
To give another example, and this expression isn't meant to do anything, but bear with me please. If I say
None is None == None
it returns True. But both of the following return False.
None is (None == None)
(None is None) == None
So clearly, Python isn't evaluating these with some strict precedence, but I'm confused what is going on. How is it evaluating this expression with 2 different operators, but differently from either order?

What you see here is operator chaining and there is no precedence involved at all!
Python supports expressions like
1 < a < 3
To test that a number is in between 1 and 3; it's equal to (1 < a) and (a < 3) except that a is only evaluated once.
Unfortunately that also means that e.g.
None is None == None
actually means
(None is None) and (None == None)
which is of course True, and the longer example you started with
a = b = 3
a is None == b is None
means
(a is None) and (None == b) and (b is None)
which can only be True if both a and b are None.
Documentation here, see the bit about chaining.
Very useful sometimes but it also pops up when you least expect it!

According to the documentation, all python comparisons operators has same priority:
There are eight comparison operations in Python. They all have the
same priority (which is higher than that of the Boolean operations).
However by wrapping comparisons with the brackets, they start to be the atoms expressions, so statements in brackets evaluated before statements outside, that impacts the order of the evalutation, I will decompose the first "contradictional" case, the all others is similar:
a = b = 3
a is None == b is None
Per documentation the priority is the same, so evaluation is next:
1. a is None ? -> False # Because a == 3
2. False == b -> False # Because b == 3
3. False is None
Please see order for the second case below:
(a is None) == (b is None)
1. a is None ? -> False # Because a == 3
2. b is None -> False # Because b == 3
3. False is False -> True

Related

and operation in python

Following is the code that is yielding confusing results.
a = None
b = 1
print a and b
if a and b is None:
print "True"
else:
print "False"
Here bool(a) is false as it's none. So via short circuit, the expression should return None. This is actually happening. However, during if condition, the condition fails. Although a and b yields None, the condition fails and priting false at the output. Can someone explain why it's happening?
a and b is None is evaluated the same as a and (b is None), so the expression evaluates to None, and execution jumps to the else clause.
If you add brackets (a and b) is None, then your code will print "True" as you expect.
This is because is has a higher precedence than and in Python. Take a look at the operator precedence documentation for more details.

if a or b explanation

a = None
b = 'Test'
if a is None or b is None:
print('Test')
this version is obviously working but:
if (a or b) is None:
print('Test')
Expected would be the same result but it evaluates to False, why?
In Python, an or statement does not just return True or False, it returns the first of it's arguments that is "truthy".
In your code, the following happens when evaluating (a or b) is None:
None is falsy, and a is None, so a or b returns b.
b is not None.
(a or b) is None resolves to False.
Operator precedence and evaluation rules of boolean expressions work a bit different in Python. This is not doing what you imagine:
(a or b) is None
The above condition is asking whether the result of evaluating (a or b) is None, and it will never be None with the current values of a and b; a or b will return 'Test' (the value of b), because a is None. If you want to test if either one of two values is None, only the first syntax is valid:
a is None or b is None
Just to be clear, in Python x or y will return the value of the first non-false expression, and None, [], {}, '', 0 and False are considered false. If what you want is to shorten the expression a bit, this is equivalent to the first version of your code:
if not a or not b:
If you want to be super brief, you can used the following construction:
if None in (a, b):
print('Test')
Please note that while this will work in the majority of cases, the expression is not exactly equivalent to a is None or b is None but rather a == None or b == None. See explanation of why this is not the same thing.

"A is not B" vs "A is (not B)"

I'm a little bit scared about the "is not" operator and the possibility that "is not X" is interpreted when "is (not X)" was intended. Do exist some expressions A and B such that:
A is not B
is different from
A is (not B)
?
addendum.
Is it considered good practice to use this operator? Should't not (A is B) be preferred?
They're definitely different. The latter case evaluates not X in a boolean context first and then checks to see if the two objects are the same object (either True or False).
Consider:
False is not []
This expression is trivially True since False and [] are quite clearly different objects. 1
vs.
False is (not [])
This expression is False since not [] evalutes to True and False and True are different objects.
Of course, this is just one example. It gets even easier to find examples if you don't use False and True explicitly as the second expression will always be False and the first expression will (almost) always be True...
3 is not 0 # True
3 is (not 0) # False
1Note that is not is a single operator in the same vein as not in.
Yes:
A = 0
B = 1
Try it and you'll be really scared:
>>> A = 0
>>> B = 1
>>> A is not B
True
>>> A is (not B)
False

Intricacies in Python's parser

In what order are the contents of the expression"word" in [] == False parsed? It seems to defy all logic:
>>> "word" in [] == False
False
>>> ("word" in []) == False
True
>>> "word" in ([] == False)
TypeError
How does Python actually interpret this expression, and why does it interpret it so?
Edit:
the most general case seems to be
>>> any_value in any_list == any_symbol_or_value
False
Normally you can find out operator precedence with this table..
But this is actually a tricky example:
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).
See the notes on comparisons.
So "word" in [] == False is really
("word" in []) and ([] == False)
where the two [] are actually the same object.
This is useful for other comparisons, ie 0 < a < 10, but really confusing here!
word in [] is short-circuiting the first expression due to an implicit and. When it realizes that it's false, it stops evaluating the rest of the expression, which is a comparison between [] (the same entity that word was just testing against) and the value False. [] does not equal False, so the implicit "and" expression is false.
("word" in []) == False works as expected because ( ) makes the sub-clause finish and have its result compared to False.
Of course, once again, [] does not equal False.
To clarify the first case, you might test it like this:
foo = []
if ("word" in foo) and (foo == False):
print "True"
else:
print "False"
This is, functionally, what's going on.

Is it safe to replace '==' with 'is' to compare Boolean-values

I did several Boolean Comparisons:
>>> (True or False) is True
True
>>> (True or False) == True
True
It sounds like == and is are interchangeable for Boolean-values.
Sometimes it's more clear to use is
I want to know that:
Are True and False pre-allocated in python?
Is bool(var) always return the same True(or False) with the pre-allocated True(or False)?
Is it safe to replace == with is to compare Boolean-values?
It's not about Best-Practice.
I just want to know the Truth.
You probably shouldn't ever need to compare booleans. If you are doing something like:
if some_bool == True:
...
...just change it to:
if some_bool:
...
No is or == needed.
As commenters have pointed out, there are valid reasons to compare booleans. If both booleans are unknown and you want to know if one is equal to the other, you should use == or != rather than is or is not (the reason is explained below). Note that this is logically equivalent to xnor and xor respectively, which don't exist as logical operators in Python.
Internally, there should only ever be two boolean literal objects (see also the C API), and bool(x) is True should be True if bool(x) == True for any Python program. Two caveats:
This does not mean that x is True if x == True, however (eg. x = 1).
This is true for the usual implementation of Python (CPython) but might not be true in other implementations. Hence == is a more reliable comparison.
Watch out for what else you may be comparing.
>>> 1 == True
True
>>> 1 is True
False
True and False will have stable object ids for their lifetime in your python instance.
>>> id(True)
4296106928
>>> id(True)
4296106928
is compares the id of an object
EDIT: adding or
Since OP is using or in question it may be worth pointing this out.
or that evaluates True: returns the first 'True' object.
>>> 1 or True
1
>>> 'a' or True
'a'
>>> True or 1
True
or that evaluates False: returns the last 'False' object
>>> False or ''
''
>>> '' or False
False
and that evaluates to True: returns the last 'True' object
>>> True and 1
1
>>> 1 and True
True
and that evaluates to False: returns the first 'False' object
>>> '' and False
''
>>> False and ''
False
This is an important python idiom and it allows concise and compact code for dealing with boolean logic over regular python objects.
>>> bool([])
False
>>> bool([0])
True
>>> bool({})
False
>>> bool({False: False})
True
>>> bool(0)
False
>>> bool(-1)
True
>>> bool('False')
True
>>> bool('')
False
Basically 'empty' objects are False, 'non empty' are True.
Combining this with #detly's and the other answers should provide some insight into how to use if and bools in python.
Yes. There are guaranteed to be exactly two bools, True and False:
Class bool cannot be subclassed
further. Its only instances are False
and True.
That means if you know both operands are bool, == and is are equivalent. However, as detly notes, there's usually no reason to use either in this case.
It seems that all answers deal with True and False as defined after an interpreter startup. Before booleans became part of Python they were often defined as part of a program. Even now (Python 2.6.6) they are only names that can be pointed to different objects:
>>> True = 1
>>> (2 > 1)
True
>>> (2 > 1) == True
True
>>> (2 > 1) is True
False
If you have to deal with older software, be aware of that.
The == operator tests for equality The is keyword tests for object identity. Whether we are talking about the same object. Note, that more variables may refer to the same object.
== and is are both comparison operators, which would return a boolean value - True or False. True has a numeric value of 1 and False has a numeric value of 0.
The operator == compare the values of two objects and objects compared are most often are the same types (int vs int, float vs float), If you compare objects of different types, then they are unequal. The operator is tests for object identity, 'x is y' is true if both x and y have the same id. That is, they are same objects.
So, when you are comparing if you comparing the return values of same type, use == and if you are comparing if two objects are same (be it boolean or anything else), you can use is.
42 is 42 is True and is same as 42 == 42.
Another reason to compare values using == is that both None and False are “falsy” values. And sometimes it’s useful to use None to mark a value as “not defined” or “no value” while considering True and False values to work with:
def some_function(val = None):
"""This function does an awesome thing."""
if val is None:
# Values was not defined.
elif val == False:
# User passed boolean value.
elif val == True:
# User passed boolean value.
else:
# Quack quack.
Somewhat related question: Python != operation vs “is not”.

Categories

Resources