My assertion fails for this piece of code in python - python

def test_string_membership():
assert False == 'c' in 'apple'
assert True == 'a' in 'apple'
assert True == 'app' in 'apple'
p.s:- I am a beginner in python and unable to find out whats wrong. My assertion fails when I run the code.

False == 'c' in 'apple' is not interpreted as
False == ('c' in 'apple')
but,
(False == 'c') and ('c' in apple)
becaue of comparison chaining.
To get what you want, put parentheses explicitly.
False == ('c' in 'apple')
or more preferably use in / not in:
def test_string_membership():
assert 'c' not in 'apple'
assert 'a' in 'apple'
assert 'app' in 'apple'

You have a problem with comparison chaining, the Python syntax that treats:
x < y < z
as:
x < y and y < z.
In your case, that means the expression False == 'c' in 'apple' is being treated as:
(False == 'c') and ('c' in 'apple')
both of which are false, hence causing the assertion. Details on comparison chaining for Python 3 can be found here.
So the way to avoid this chianing is to make the expression explicit, with something like:
assert False == ('c' in 'apple')
assert True == ('a' in 'apple')
assert True == ('app' in 'apple')
or, even better, since comparing with true/false is rarely a good idea:
assert 'c' not in 'apple' # or "not('c' in 'apple')" if you're testing 'in'.
assert 'a' in 'apple'
assert 'app' in 'apple'

Contrary to the other answers, what is happening here is not operator precedence but comparison chaining. a == b in c means (a == b) and (b in c), just like a < b < c means (a < b) and (b < c). However, in either case, the upshot is the same, which is that it's not what you meant to do. As noted in the other answers and comments, it can be fixed by using parentheses, or, better, by not using an equality comparison at all and just doing assert 'c' not in 'apple'.
You can see that this is comparison chaining by a slightly different example:
>>> 'a' == 'a' in 'ab'
True
This would obviously be false no matter which way the precedence went, but it is true because 'a' == 'a' and 'a' in 'ab' are both true.

Using parenthesis should solve this as in
def test_string_membership():
assert False == ('c' in 'apple')
assert True == ('a' in 'apple')
assert True == ('app' in 'apple')

You may use () in this case. There are better ways to do what you are trying.
def test_string_membership():
assert False == ('c' in 'apple')
assert True == ('a' in 'apple')
assert True == ('app' in 'apple')
This is because of precedence. Read more about this on Python docs.
in, not in, is, is not, <, <=, >, >=, <>, !=, == are in the same precedence level. So Python will evaluate
False == 'c' in 'apple'
from left to right.

Related

Python "in" and "==" confusion

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))

Why are this operands returning False?

I have a counter-intuitive issue while writing my script in Python.
>>> def foo():
... return False
...
>>> foo()
False
>>> foo()==False
True
>>> i=1
>>> i!=0
True
>>> foo()==False & i!=0
False
>>> (foo()==False) & i!=0
True
>>>
As you can see foo()==False returns True as i!=0 does, so intuitively I would expect True & True to return True, however when I run foo()==False & i!=0 I receive False and when I run (foo()==False) & i!=0 I get True as was initially expected. What is going on here?
It's simple pythons order of operations. In
foo()==False & i!=0
the bitwise and & has a higher precedence than the ==. Thus, you're really evaluating
foo()==(False & i)!=0
If you replace your bitwise and & with a logical and and, your answer comes out as expected
>>> foo()==False and i!=0
True
Read more about it here
& has higher precedence than == and != in python so use (foo()==False) & (i!=0) to make sure that no operand precedence conflict occurs.
The reason is that there is operator precedence in python, refer to the doc:
Comparisons(==,!=) has lower precedence than Bitwise AND(&):
foo()==False & i!=0 ==> foo()==(False & i)!=0
(foo()==False) & i!=0 ==> ((foo()==False) & i)!=0
& is the Bitwise operator, you can use it to see if a number is even or odd. Since foo() returns False which is considered 0 and 0 is not considered an odd number, theBitwise operator & will return False because is not an odd number.
As per python documentation 6.16. Operator precedence & has higher precedence than == or !=
therefore when you run foo()==False & i!=0 is evaluated as follows
foo()==False & i!=0
foo() == (False & True)!= 0 #since 1 is nothing but True
Foo() == False != False
which is false.
https://docs.python.org/3/reference/expressions.html#summary
I initially tried to include a table but dont know how to do that in stackoverflow. sorry.

Why is `True is False == False`, False in Python? [duplicate]

This question already has an answer here:
Why does (1 in [1,0] == True) evaluate to False?
(1 answer)
Closed 7 years ago.
Why is it that these statements work as expected when brackets are used:
>>> (True is False) == False
True
>>> True is (False == False)
True
But it returns False when there are no brackets?
>>> True is False == False
False
Based on python documentation about operator precedence :
Note that comparisons, membership tests, and identity tests, all have the same precedence and have a left-to-right chaining feature as described in the Comparisons section.
So actually you have a chained statement like following :
>>> (True is False) and (False==False)
False
You can assume that the central object will be shared between 2 operations and other objects (False in this case).
And note that its also true for all Comparisons, including membership tests and identity tests operations which are following operands :
in, not in, is, is not, <, <=, >, >=, !=, ==
Example :
>>> 1 in [1,2] == True
False
Python has a unique transitive property when it comes to the comparison operators. It will be easier to see in a simpler case.
if 1 < x < 2:
# Do something
This does what it looks like. It checks if 1 < x and if x < 2. The same thing is happening in your non-parenthesized code.
>>> True is False == False
False
It is checking whether True is False and False == False, only one of which is true.
This is a double inequality which gets expanded as (True is False) and (False == False). See for instance What is the operator precedence when writing a double inequality in Python (explicitly in the code, and how can this be overridden for arrays?)
Python interprets multiple (in)equalities the way you would expect in Math:
In Math a = b = c mean all a = b, b = c and a = c.
So True is False == False means True == False and False == False and True == False, which is False.
For boolean constants, is is equivalent to ==.
Python performs chaining if it encounters operators of same precedence when evaluating an expression.
comparisons, including tests, which all have the same precedence
chain from left to right
The below mentioned operators have the same precedence.
in, not in, is, is not, <, <=, >, >=, <>, !=, ==
So, when Python tries to evaluate the expression True is False == False, it encounters the operators is and == which have the same precedence, so it performs chaining from left to right.
So, the expression True is False == False is actually evaluated as:
(True is False) and (False == False)
giving False as the output.

What should be simple expression (containing less_than, is, and) result? Why? [duplicate]

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.

How does python interpret "True != True != True"? [duplicate]

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.

Categories