This question already has answers here:
Why does the expression 0 < 0 == 0 return False in Python?
(9 answers)
Closed 7 days ago.
The following comparisons produce True:
>>> '1' in '11'
True
>>> ('1' in '11') == True
True
And with the parentheses the other way, I get a TypeError:
>>> '1' in ('11' == True)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: argument of type 'bool' is not iterable
So how do I get False with no parentheses?
>>> '1' in '11' == True
False
The Python manual says in and == are of equal precedence. Thus, they're evaluated from left to right by default, but there's also chaining to consider. The expression you put above ('1' in '11' == True) is actually being evaluated as...
('1' in '11') and ('11' == True)
which of course is False. If you don't know what chaining is, it's what allows you to do something like...
if 0 < a < 1:
in Python, and have that mean what you expect ("a is greater than 0 but less than 1").
It has nothing to do with precedence. In Python relational operators chain, and containment is considered a relational operator. Therefore:
'1' in '11' == True
is the same as:
('1' in '11') and ('11' == True)
which is false since True is not equal to "11".
Chaining allows you to write x < y < z, and mean x < y and y < z. Look at this interaction:
>>> (False == True) == False
True
>>> False == (True == False)
True
>>> False == True == False
False
>>>
So in your example, '1' in '11' == True is equivalent to ('1' in '11') and ('11' == True)
Related
When I was looking at answers to this question, I found I didn't understand my own answer.
I don't really understand how this is being parsed. Why does the second example return False?
>>> 1 in [1,0] # This is expected
True
>>> 1 in [1,0] == True # This is strange
False
>>> (1 in [1,0]) == True # This is what I wanted it to be
True
>>> 1 in ([1,0] == True) # But it's not just a precedence issue!
# It did not raise an exception on the second example.
Traceback (most recent call last):
File "<pyshell#4>", line 1, in <module>
1 in ([1,0] == True)
TypeError: argument of type 'bool' is not iterable
Thanks for any help. I think I must be missing something really obvious.
I think this is subtly different to the linked duplicate:
Why does the expression 0 < 0 == 0 return False in Python?.
Both questions are to do with human comprehension of the expression. There seemed to be two ways (to my mind) of evaluating the expression. Of course neither were correct, but in my example, the last interpretation is impossible.
Looking at 0 < 0 == 0 you could imagine each half being evaluated and making sense as an expression:
>>> (0 < 0) == 0
True
>>> 0 < (0 == 0)
True
So the link answers why this evaluates False:
>>> 0 < 0 == 0
False
But with my example 1 in ([1,0] == True) doesn't make sense as an expression, so instead of there being two (admittedly wrong) possible interpretations, only one seems possible:
>>> (1 in [1,0]) == True
Python actually applies comparison operator chaining here. The expression is translated to
(1 in [1, 0]) and ([1, 0] == True)
which is obviously False.
This also happens for expressions like
a < b < c
which translate to
(a < b) and (b < c)
(without evaluating b twice).
See the Python language documentation for further details.
print('a' in 'aa')
print('a' in 'aa' == True)
print(('a' in 'aa') == True)
print('a' in ('aa' == True))
The output is
True
False
True
Traceback (most recent call last):
File "main.py", line 6, in <module>
print('a' in ('aa' == True))
TypeError: argument of type 'bool' is not iterable
If line 2 is neither line 3 nor line 4, then what is it? How does it get False?
According to Expressions
print('a' in 'aa' == True)
is evaluated as
'a' in 'aa' and 'aa' == True
which is False.
See
print("a" in "aa" and "aa" == True)
==> False
The rest is trivial - it helps to keep operator precedence in mind to figure them out.
Similar ones:
Multiple comparison operators in single statement
Why does the expression 0 < 0 == 0 return False in Python?
with different statements. I flagged for dupe but the UI is wonky - I answered non the less to explain why yours exactly printed what it did.
Case 1 : it's simple the answers is True.
print('a' in 'aa')
Case 2 : This operation is evaluated as 'a' in 'aa' and 'aa' == True, so obviously it will return false.
print('a' in 'aa' == True)
Case 3: Now because we have () enclosing ('a' in 'aa') and the precedence of () is highest among all so first 'a' in 'aa' is evaluated as True and then True == True
print(('a' in 'aa') == True)
Case 4 : Same as above because of precedence of (), its evaluated as 'aa' == True, which will result in error as it tries to apply in on a non iterable that is bool value.
print('a' in ('aa' == True))
When I was looking at answers to this question, I found I didn't understand my own answer.
I don't really understand how this is being parsed. Why does the second example return False?
>>> 1 in [1,0] # This is expected
True
>>> 1 in [1,0] == True # This is strange
False
>>> (1 in [1,0]) == True # This is what I wanted it to be
True
>>> 1 in ([1,0] == True) # But it's not just a precedence issue!
# It did not raise an exception on the second example.
Traceback (most recent call last):
File "<pyshell#4>", line 1, in <module>
1 in ([1,0] == True)
TypeError: argument of type 'bool' is not iterable
Thanks for any help. I think I must be missing something really obvious.
I think this is subtly different to the linked duplicate:
Why does the expression 0 < 0 == 0 return False in Python?.
Both questions are to do with human comprehension of the expression. There seemed to be two ways (to my mind) of evaluating the expression. Of course neither were correct, but in my example, the last interpretation is impossible.
Looking at 0 < 0 == 0 you could imagine each half being evaluated and making sense as an expression:
>>> (0 < 0) == 0
True
>>> 0 < (0 == 0)
True
So the link answers why this evaluates False:
>>> 0 < 0 == 0
False
But with my example 1 in ([1,0] == True) doesn't make sense as an expression, so instead of there being two (admittedly wrong) possible interpretations, only one seems possible:
>>> (1 in [1,0]) == True
Python actually applies comparison operator chaining here. The expression is translated to
(1 in [1, 0]) and ([1, 0] == True)
which is obviously False.
This also happens for expressions like
a < b < c
which translate to
(a < b) and (b < c)
(without evaluating b twice).
See the Python language documentation for further details.
As expected, 1 is not contained by the empty tuple
>>> 1 in ()
False
but the False value returned is not equal to False
>>> 1 in () == False
False
Looking at it another way, the in operator returns a bool which is neither True nor False:
>>> type(1 in ())
<type 'bool'>
>>> 1 in () == True, 1 in () == False
(False, False)
However, normal behaviour resumes if the original expression is parenthesized
>>> (1 in ()) == False
True
or its value is stored in a variable
>>> value = 1 in ()
>>> value == False
True
This behaviour is observed in both Python 2 and Python 3.
Can you explain what is going on?
You are running into comparison operator chaining; 1 in () == False does not mean (1 in ()) == False.
Rather, comparisons are chained and the expression really means:
(1 in ()) and (() == False)
Because (1 in ()) is already false, the second half of the chained expression is ignored altogether (since False and something_else returns False whatever the value of something_else would be).
See the comparisons expressions documentation:
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).
For the record, <, >, ==, >=, <=, !=, is, is not, in and not in are all comparison operators (as is the deprecated <>).
In general, don't compare against booleans; just test the expression itself. If you have to test against a boolean literal, at least use parenthesis and the is operator, True and False are singletons, just like None:
>>> (1 in ()) is False
True
This gets more confusing still when integers are involved. The Python bool type is a subclass of int1. As such, False == 0 is true, as is True == 1. You therefor can conceivably create chained operations that almost look sane:
3 > 1 == True
is true because 3 > 1 and 1 == True are both true. But the expression:
3 > 2 == True
is false, because 2 == True is false.
1 bool is a subclass of int for historic reasons; Python didn't always have a bool type and overloaded integers with boolean meaning just like C does. Making bool a subclass kept older code working.
As expected, 1 is not contained by the empty tuple
>>> 1 in ()
False
but the False value returned is not equal to False
>>> 1 in () == False
False
Looking at it another way, the in operator returns a bool which is neither True nor False:
>>> type(1 in ())
<type 'bool'>
>>> 1 in () == True, 1 in () == False
(False, False)
However, normal behaviour resumes if the original expression is parenthesized
>>> (1 in ()) == False
True
or its value is stored in a variable
>>> value = 1 in ()
>>> value == False
True
This behaviour is observed in both Python 2 and Python 3.
Can you explain what is going on?
You are running into comparison operator chaining; 1 in () == False does not mean (1 in ()) == False.
Rather, comparisons are chained and the expression really means:
(1 in ()) and (() == False)
Because (1 in ()) is already false, the second half of the chained expression is ignored altogether (since False and something_else returns False whatever the value of something_else would be).
See the comparisons expressions documentation:
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).
For the record, <, >, ==, >=, <=, !=, is, is not, in and not in are all comparison operators (as is the deprecated <>).
In general, don't compare against booleans; just test the expression itself. If you have to test against a boolean literal, at least use parenthesis and the is operator, True and False are singletons, just like None:
>>> (1 in ()) is False
True
This gets more confusing still when integers are involved. The Python bool type is a subclass of int1. As such, False == 0 is true, as is True == 1. You therefor can conceivably create chained operations that almost look sane:
3 > 1 == True
is true because 3 > 1 and 1 == True are both true. But the expression:
3 > 2 == True
is false, because 2 == True is false.
1 bool is a subclass of int for historic reasons; Python didn't always have a bool type and overloaded integers with boolean meaning just like C does. Making bool a subclass kept older code working.