Python's in (_Contains_) Operator Returns a Bool Whose Value Is Neither True Nor False

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

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.

Python things which are neither True nor False

a is a one-member tuple, which evaluates to True. is test identity of the object, therefore, you get False in all those test. == test equality of the objects, therefore, you get False again.

in if statement a __bool__ (or __nonzero__) used to evaluate the object, for a non-empty tuple it should return True, therefore you get True. hope that answers your question.

edit: the reason True and False are equal to 1 and 0 respectively is because bool type implemented as a subclass of int type.

Can someone explain to me what python is doing here?

This is a chained comparison (see here in the docs), the same way that

>>> 1 < 2 < 3
True

is

>>> (1 < 2) and (2 < 3)
True

In this case, we have

>>> 3 > 2 == True
False

because

>>> (3 > 2) and (2 == True)
False

because

>>> (3 > 2), (2 == True)
(True, False)

What is the use of assert in Python?

The assert statement exists in almost every programming language. It has two main uses:

  1. It helps detect problems early in your program, where the cause is clear, rather than later when some other operation fails. A type error in Python, for example, can go through several layers of code before actually raising an Exception if not caught early on.

  2. It works as documentation for other developers reading the code, who see the assert and can confidently say that its condition holds from now on.

When you do...

assert condition

... you're telling the program to test that condition, and immediately trigger an error if the condition is false.

In Python, it's roughly equivalent to this:

if not condition:
raise AssertionError()

Try it in the Python shell:

>>> assert True # nothing happens
>>> assert False
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError

Assertions can include an optional message, and you can disable them when running the interpreter.

To print a message if the assertion fails:

assert False, "Oh no! This assertion failed!"

Do not use parenthesis to call assert like a function. It is a statement. If you do assert(condition, message) you'll be running the assert with a (condition, message) tuple as first parameter.

As for disabling them, when running python in optimized mode, where __debug__ is False, assert statements will be ignored. Just pass the -O flag:

python -O script.py

See here for the relevant documentation.

Boolean logic in Python

From the documentation:

The expression x and y first evaluates x; if x is false, its value is returned; otherwise, y is evaluated and the resulting value is returned.

The expression x or y first evaluates x; if x is true, its value is returned; otherwise, y is evaluated and the resulting value is returned.

Note that here, if x is false means if bool(x) == False.

What does the following line accomplish?

As can be seen in the Python docs, Python logical operators are not necessarily "purely Boolean". In particular, and and or are not actually guaranteed to return True or False. Instead, they return one of their operands. Here's how Python defines the value of x and y:

if x is false, then x, else y

"False" in this context does not mean that x has to be the value False. Instead, it just has to be anything with a falsy value, like a zero of any type or an empty sequence or collection.

In this case, when n > 1 evaluates False, the operator short-circuits and returns n > 1, AKA False. But if n > 1 evaluates True, the operator simply returns n without modifying it in any way, as the docs describe.

How do Python's any and all functions work?

You can roughly think of any and all as series of logical or and and operators, respectively.

any

any will return True when at least one of the elements is Truthy. Read about Truth Value Testing.

all

all will return True only when all the elements are Truthy.

Truth table

+-----------------------------------------+---------+---------+
| | any | all |
+-----------------------------------------+---------+---------+
| All Truthy values | True | True |
+-----------------------------------------+---------+---------+
| All Falsy values | False | False |
+-----------------------------------------+---------+---------+
| One Truthy value (all others are Falsy) | True | False |
+-----------------------------------------+---------+---------+
| One Falsy value (all others are Truthy) | True | False |
+-----------------------------------------+---------+---------+
| Empty Iterable | False | True |
+-----------------------------------------+---------+---------+

Note 1: The empty iterable case is explained in the official documentation, like this

any

Return True if any element of the iterable is true. If the iterable is empty, return False

Since none of the elements are true, it returns False in this case.

all

Return True if all elements of the iterable are true (or if the iterable is empty).

Since none of the elements are false, it returns True in this case.


Note 2:

Another important thing to know about any and all is, it will short-circuit the execution, the moment they know the result. The advantage is, entire iterable need not be consumed. For example,

>>> multiples_of_6 = (not (i % 6) for i in range(1, 10))
>>> any(multiples_of_6)
True
>>> list(multiples_of_6)
[False, False, False]

Here, (not (i % 6) for i in range(1, 10)) is a generator expression which returns True if the current number within 1 and 9 is a multiple of 6. any iterates the multiples_of_6 and when it meets 6, it finds a Truthy value, so it immediately returns True, and rest of the multiples_of_6 is not iterated. That is what we see when we print list(multiples_of_6), the result of 7, 8 and 9.

This excellent thing is used very cleverly in this answer.


With this basic understanding, if we look at your code, you do

any(x) and not all(x)

which makes sure that, atleast one of the values is Truthy but not all of them. That is why it is returning [False, False, False]. If you really wanted to check if both the numbers are not the same,

print [x[0] != x[1] for x in zip(*d['Drd2'])]


Related Topics



Leave a reply



Submit