tonysdg
tonysdg

Reputation: 1385

Why does (not None) == True evaluate to True?

This tripped me up recently in a piece of Python code - I was checking if any of the values in a list were False, so I used something like:

if any(not v for v in values):
    # Do something...

However, I forgot that there were None values in the list, so I kept getting confusing outputs until I remembered to check for that first. That got me wondering though - what's the rationale behind (not None) == True? None == False evaluates to False, so it's not reflexive, and it's not immediately clear to me why the logical negation of the None object should evaluate to True.

Upvotes: 1

Views: 2647

Answers (3)

Martijn Pieters
Martijn Pieters

Reputation: 1121366

not is an operator that produces a boolean value, the inverse of the truth value of it's operand.

I suspect you are confusing the truth value with the boolean value. The latter is only either True or False, but the truth value of any Python object can be converted to a boolean value by passing it to the bool() function. Statements like if and while, operators like and, or and not test for truth values, not specifically boolean values. any() and all() test each value in the iterable for truth as well.

As such, you should never need to do if some_expression == True or if not some_expression == True when testing truth values. Just use if some_expression or if not some_expression.

Note that not has to return a boolean value because you can't, usually, invert a truth value. What would the inverse be of 0 or an empty list, for example? 0 is considered false, but any other integer would be considered true, so what value would not 0 return if not False? For lists, what would you put in the list to produce not []?

Upvotes: 4

Projski
Projski

Reputation: 181

This answer to a related question contains some good info you may want to check out, explaining detail about the use of True, False, and None in Python: https://stackoverflow.com/a/9494887/4174975

An explanation that's perhaps more specific to your answer can be found in the O'Reilly book Introducing Python by Bill Lubanovic, who refers to Python programs that use the concept of "truthiness" and "falsiness" to check for empty data structures as well as False conditions. The author even has a subsection on page 88 titled "None is Useful" which elaborates:

None is a special Python value that holds a place when there is nothing to say. It is not the same as the boolean value False, although it looks false when evaluated as boolean. [...] You'll need None to distinguish a missing value from an empty value... zero-valued integers or floats, empty string (''), lists([]), tuples((,)), dictionaries({}), and sets(set()) are all False, but are not equal to None.

So that is the rationale behind why None behaves the way that it does, and has subtle qualities apart from what you get with True and False or a 1 or a 0.

As to the other part of your question, it appears to be a logical tautology: None is False because Python interprets the None as being the equivalent of a null for the reasons found above. By adding not to a None, you are inverting its boolean value, which turns it into a True.

Upvotes: 0

Spade
Spade

Reputation: 2280

The explanation for why it happens is in the comments to your question. A good way to check if anything within your list evaluates to false is:

if not all(values):

There are many ways to do what you're doing but this for me is more readable than the list comprehension you have.

Upvotes: 0

Related Questions