5

If not '' evaluates to True, why does '' == False evaluates to False?

For example, the "voids" of the other types (e.g. 0, 0.0) will return True when compared to False:

>>> 0 == False
True
>>> 0.0 == False
True

Thanks

nalzok
  • 14,965
  • 21
  • 72
  • 139
Tony Power
  • 1,033
  • 11
  • 23
  • 1
    empty sequence evaluates to `False`, but does not equal `False`. Read here: http://stackoverflow.com/a/9573259/6313992 (top 2 answers cover this) – Tomasz Plaskota Aug 16 '16 at 10:38
  • 1
    Thanks. Nevertheless, my question remains: Why? – Tony Power Aug 16 '16 at 10:46
  • @TonyPower Because this is how Python was chosen to be implemented. There's no real answer for the question "why". Also, why would an empty list be *equal* to False? it is still a list, just an empty one. – DeepSpace Aug 16 '16 at 10:51

5 Answers5

10

In the context of Boolean operations, and also when expressions are used by control flow statements, the following values are interpreted as false: False, None, numeric zero of all types, and empty strings and containers (including strings, tuples, lists, dictionaries, sets and frozensets). All other values are interpreted as true. User-defined objects can customize their truth value by providing a __bool__() method.

The operator not yields True if its argument is false, False otherwise.

https://docs.python.org/3/reference/expressions.html#comparisons

But:

The operators <, >, ==, >=, <=, and != compare the values of two objects. The objects do not need to have the same type.

...

Because all types are (direct or indirect) subtypes of object, they inherit the default comparison behavior from object. Types can customize their comparison behavior by implementing rich comparison methods like __lt__() ...

https://docs.python.org/3/reference/expressions.html#boolean-operations

So, the technical implementation answer is that it behaves the way it does because not and == use different comparisons. not uses __bool__, the "truth value" of an object, while == uses __eq__, the direct comparison of one object to another. So it's possible to ask an object whether it considers itself to be truthy or falsey, and separately from that ask it whether it considers itself to be equal to another object or not. The default implementations for that are arranged in a way that two objects can both consider themselves falsey yet not consider themselves equal to one another.

Community
  • 1
  • 1
deceze
  • 510,633
  • 85
  • 743
  • 889
6

It doesn't make sense for '' and [] to actually equal False, because they are clearly different values: a string and a list. If they both equalled False they would have to be equal to each other*. They are just "falsey", which means they come out as false when they are converted to a boolean.

(* in any sensibly constructed language)

not is an operation that returns a boolean. Which boolean it returns depends on whether the operand is falsey or not. So not x is not equivalent to x==False; it is equivalent to bool(x)==False.

khelwood
  • 55,782
  • 14
  • 81
  • 108
  • 1
    *cough* Behold PHP's logic: `[] == false; '' == false; [] != '';` Yup… – deceze Aug 16 '16 at 10:45
  • Hence my note at * – khelwood Aug 16 '16 at 10:45
  • So, you are saying that it is not sensible to say that `''` is `False` but it makes sense to say that `0` is? I know boolean logic is all about zeroes and ones, nevertheless, it makes as much sense to me to say that `''` is `False` as it makes sense saying `not ''` is True. – Tony Power Aug 16 '16 at 10:52
  • The Python expression `'' is False` evaluates false, because `is` only returns True when the operands are references to the same object. `'' is True` also evaluates false, for exactly the same reason. – holdenweb Aug 16 '16 at 10:55
  • 1
    @TonyPower In Python `bool` is a subclass of `int`. This is not true of `list` or `str`. Basically `False` and `True` are just special instances of `0` and `1`. eg. `True + 2 == 3`, whereas `[] + 2` gives an error. If they are equal, then you need to be able to perform other types of operation with the strings and lists and ints. – Dunes Aug 16 '16 at 10:55
1

Such a comparison isn't "Pythonic" (i.e. it isn't what an experienced Python programmer would naturally do). The Pythonic way to proceed is to use a value in a Boolean context such as an if statement, and leave the interpreter to apply the bool built-in invisibly to determine a True or False value. That's why people commonly write code such as

if lst:
    print(headers)
    for item in lst:
        print(item.format())
else:
    print(no_data_message)

rather than using the commonly-seen but less Pythonic if len(lst): or the even clumsier but still functionally correct if len(lst) > 0:.

In some respects unfortunately, Python's designer decided that True and False would be instances of the bool type, and that bool would be a subclass of int. As a result of this True compares equal to 1 and False compares equal to 0. Numerical conversion accounts for the floating-point (and, for that matter, complex) result.

But just because a bool(x) == True doesn't mean x == True, any more than bool(x) == False implies x == False. There are many other values that evaluate false, the best-known being

  • Numeric zeroes
  • None
  • The empty string
  • Empty containers (list, tuple, dict)

There's no way they can all be equal to each other!

holdenweb
  • 33,305
  • 7
  • 57
  • 77
  • 1
    It makes sense. Thanks. – Tony Power Aug 16 '16 at 12:38
  • 1
    This was the most valuable response for me in this question, since it actually explains *why* the `__eq__` operator behaves this way -- because bool is a subtype of int. That was the missing insight for me on this piece of Python's language design. – opatut Jul 28 '21 at 07:53
0

Because int(False) == 0 and int(True) == 1. This is what Python is doing when it tries to evaluate 0 == False.

On the other hand, bool('') == False. The same goes for bool([]) and bool({}).

The fact that x evaluates to True doesn't necessarily mean that x == True.

DeepSpace
  • 78,697
  • 11
  • 109
  • 154
  • And if you switch things around? For example: `False == 0` Is it doing `False == bool(0)`? If so, it should do the same with the empty string, and is not doing it. – Tony Power Aug 16 '16 at 10:42
  • "That is the reason that `is` should be used in checks against a boolean value and not `==`" -- I don't see how this follows – khelwood Aug 16 '16 at 10:48
  • The tests `x is True` and `x is False` are, for most values of `x`, both False, so your advice that `is` should be used is dangerously wrong. – holdenweb Aug 16 '16 at 10:57
  • Also, understand the mechanism that is used. The interpreter applies the `bool` function to values. `bool` returns either `True` or `False`. – holdenweb Aug 17 '16 at 08:40
0

If you want to check the official explanation, just cast your values like this:

print(bool(None) == False)
print(False == False)
print(bool(0) == False)
print(bool(0.0) == False)
print(bool(0j) == False)
print(bool('') == False)
print(bool(()) == False)
print(bool([]) == False)
print(bool({}) == False)
BPL
  • 9,632
  • 9
  • 59
  • 117