Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python's in (__contains__) operator returns a bool whose value is neither True nor False

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?

like image 489
user2949478 Avatar asked Nov 03 '13 09:11

user2949478


People also ask

What is Boolean operators in Python?

PythonServer Side ProgrammingProgramming. The logical operators and, or and not are also referred to as boolean operators. While and as well as or operator needs two operands, which may evaluate to true or false, not operator needs one operand evaluating to true or false.

How to check boolean values in Python?

We can evaluate values and variables using the Python bool() function. This method is used to return or convert a value to a Boolean value i.e., True or False, using the standard truth testing procedure.

What is a boolean value in Python?

To represent true and false, Python provides you with the boolean data type. The boolean value has a technical name as bool . The boolean data type has two values: True and False . Note that the boolean values True and False start with the capital letters ( T ) and ( F ).


1 Answers

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.

1bool 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.

like image 67
Martijn Pieters Avatar answered Sep 29 '22 07:09

Martijn Pieters