1

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.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
tonysdg
  • 1,335
  • 11
  • 32
  • 1
    `(not None) == True` produces `True`. – Martijn Pieters May 06 '16 at 17:59
  • Whoops, that's what I meant - sorry! – tonysdg May 06 '16 at 18:00
  • 4
    `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 `True` or `False`, truth value can be *converted* to a boolean value by passing it to the `bool()` function. – Martijn Pieters May 06 '16 at 18:01
  • 2
    Since `None` is a falsy value, it seems logical that `not None` is a truthy value. What is it that confuses you exactly? – Vincent Savard May 06 '16 at 18:01
  • 1
    Side note: using a list comprehension inside `any()` or `all()` completely defeats the purpose of those functions. Use a generator expression, always. – Martijn Pieters May 06 '16 at 18:01
  • @VincentSavard: `not None` is not only a truthy value. It is a *boolean* value. `None` itself, however, is not a boolean value. – Martijn Pieters May 06 '16 at 18:02
  • @MartijnPieters Indeed. I'm just explaining the thought process you can infer from knowing that `None` is a falsy value. After all, `True` _is_ a truthy value. :) – Vincent Savard May 06 '16 at 18:04
  • @MartijnPieters: I've never head of *truth values* - I assumed they were the same as boolean values. That answers my question - please add that as an answer and I'll mark it as such. – tonysdg May 06 '16 at 18:20
  • @VincentSavard - the confusion comes from the delineation between a truth value and a boolean value. I guess it makes sense that `None` is a falsy value - it represents a lack of something - it just wasn't an immediately obvious conclusion to me. My follow-up question then is why does `int(1) == True` but `int(5) != True`? Neither is `None`, both seem truthy from a C programmer's POV. – tonysdg May 06 '16 at 18:25
  • @tonysdg I don't have time to write a detailed answer right now, but in short. there's a slight difference (which is at the source of your confusion) between `not None == True` and `5 == True`: In one case, you're comparing `True` to a `bool` while in the other, to an `int`. If you do `bool(5) == True`, you'll notice it is `True`. – Vincent Savard May 06 '16 at 18:31
  • @tonysdg this is just like C, if `True` is defined as `1`. `int(5) != True`, but `if int(5):` will execute the following block. – Dan Getz May 06 '16 at 18:32
  • @VincentSavard - I'll take that - I'm guessing part of my confusion comes from the fact that I primarily work in C, not python, so I'm trying to apply apples to oranges. Thank you for your time! – tonysdg May 06 '16 at 18:32
  • @tonysdg: for historical reasons, `True == 1` and `False == 0`. That's because Python did not always have a `bool` type; in the good old days we used `0` and `1` instead. For the same reason, `issubclass(bool, int)` is also true, booleans are a special type of integer. See [Is False == 0 and True == 1 in Python an implementation detail or is it guaranteed by the language?](http://stackoverflow.com/q/2764017) – Martijn Pieters May 06 '16 at 18:52

3 Answers3

4

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 []?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
0

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.

Spade
  • 2,220
  • 1
  • 19
  • 29
0

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.

Community
  • 1
  • 1
Projski
  • 181
  • 8