Why does ... == True return False in Python 3?
Asked Answered
H

4

14

I am learning python, but I'm a bit confused by the following result.

In [41]: 1 == True
Out[41]: True

In [42]: if(1):
    ...:     print('111')
    ...:     
111

In [43]: ... == True
Out[43]: False <===== why this is False while '1 == True' is True in previous sample

In [44]: if (...): <==== here ... just behaves like True
    ...:     print('...')
    ...:     
...

According to the documentation, ... has a truth value of True.

But I still feel the above code a bit inconsistent.

...And something more interesting:

In [48]: 2==True
Out[48]: False <===== why 1==True returns True while 2==True returns False?

In [49]: if(2):
    ...:     print('222')
    ...:     
222
Holland answered 11/5, 2017 at 14:47 Comment(6)
bool(...) == True --> TrueKeeney
FWIW, bool(...) returns TrueOhg
@ReutSharabani Thanks but that still can't resolve my unrest about my experiment result.Holland
"Has a truth value of true" doesn't mean "== True".Allister
You are confusing evaluating to True with being equal to True. Python booleans are ints, 1 == True and 0 == False, but any(?) non-empty non-zero object evaluates to True, as you can see with bool()Cretan
1 == True is because bool inherits from int. Whether this is a good idea or not (cf Ruby) it's unlikely to change in Python. For this reason you should get into the habit of using x is True, x is False, or x is None for those situations.Marna
P
13

You're mixing two concepts: equality testing and truth-value testing. They are not the same in Python.

I think what triggered the question is that Python does an implicit casting when you do if something (it casts the something to bool) but it does not do implicit casting when you do something1 == something2.

Pythons data model actually explains how these operations are done:

Truth-value testing

  • It starts by checking if the object implements the __bool__ method and if it does it uses the returned boolean.
  • If it doesn't define a __bool__ method it looks at the __len__ method. If it's implemented it will use the result of len(obj) != 0.
  • If it doesn't have either the object is considered True.

For integers the __bool__ method returns True except when the integer value is 0 (then it's False).

The Ellipsis object (... is the Ellipsis object) on the other hand doesn't implement __bool__ or __len__ so it's always True.

Equality testing

Equality testing relies on the __eq__ method of both arguments. It's more a chain of operations:

  • It checks if the first operand implements __eq__ when the second operand is passed as argument.
  • If it doesn't then it checks if the second operand implements __eq__ when the first operand is passed as argument.
  • If it doesn't then Python checks for object identity (if they are the same object - similar to pointer comparisons in C-like languages)

The order of these operations may vary.1

For built-in Python types these operations are explicitly implemented. For example integers implement __eq__ but the CHECK_BINOP makes sure that it returns NotImplemented if the other one isn't an integer.

The Ellipsis object doesn't implement __eq__ at all.

So when you compare integers and Ellipsis Python will always fallback to object identity and so it will always return False.

On the other hand booleans are a subclass of integers so they actually compare with int (they are another int after all). The booleans are implemented as 1 (True) and 0 (False). So they compare equal:

>>> 1 == True
True
>>> 0 == False
True

>>> 1 == False
False
>>> 0 == True
False

Even though the source code is probably hard to understand I hope I explained the concepts well enough (the source code is for the CPython implementation, the implementation in other Python implementations like PyPy, IronPython may differ!). The important take-away message should be that Python doesn't do implicit conversions in equality checks and equality testing is not related to truth value testing at all. The built-in types are implemented that they almost always give senseable results:

  • all number-types implement equality in some way (floats compare to integers, complex compare to integers and floats)
  • and everything not-zero and not-empty is truthy.

However if you create your own classes you can override equality and truth value testing as you like (and then you can spread a lot of confusion)!


1 In some cases the order is changed:

  1. If the second operand is a subclass of the first operand the first two steps are reversed.
  2. For some implicit equality checks the object identity is checked before any __eq__ methods are called. For example when checking if some item is in a list, i.e. 1 in [1,2,3].
Paradis answered 11/5, 2017 at 23:27 Comment(1)
@Claudio Well, that's kind of the point I was trying to make: The casting isn't implicit it has to be implemented explicitly in either operands __eq__ method. And the built-in types don't do explicit casting, they hard-code the comparison between different types (or return False if incomparable). You might want to take a look at how complicated that get's for float == int.Paradis
P
6

Any object can be tested for "truthiness":

Any object can be tested for truth value, for use in an if or while condition or as operand of the Boolean operations below. The following values are considered false:

  • None

  • False

  • zero of any numeric type, for example, 0, 0.0, 0j.

  • any empty sequence, for example, '', (), [].

  • any empty mapping, for example, {}.

  • instances of user-defined classes, if the class defines a bool() or len() method, when that method returns the integer zero or bool value False. [1]

All other values are considered true — so objects of many types are always true.

Operations and built-in functions that have a Boolean result always return 0 or False for false and 1 or True for true, unless otherwise stated. (Important exception: the Boolean operations or and and always return one of their operands.)

So it's not hard to see that if ... will enter the branch. The Ellipsis object is considered true. However that doesn't mean it has to be equal to True. Just the bool(...) == True!

The if will implicitly call bool on the condition, so:

if ...:
    # something

will be evaluated as if you had written:

if bool(...):
    # something

and:

>>> bool(...)
True
>>> bool(1)
True
>>> bool(2)
True

However there's one catch here. True is equal to 1 and False equal to 0, but that's just because bool subclasses integer in python.

Paradis answered 11/5, 2017 at 14:56 Comment(4)
Clearest answer, I upvoted. Interesting that although if ...: always gives the same output as if bool(...):, the CPython implementation seems different, at least from a quick comparison with dis.dis()Cretan
@Cretan It's not identical because if ... will check the truth-value of ... (which is True) in the other case it will first convert ... to a boolean object (True) and then check the truth value of True (which is also True). But the result will be the same.Paradis
How does it "check the truth-value" though? That doesn't involve some kind of boolean conversion but instead some kind of look-up?Cretan
@Cretan It either uses PyObject_IsTrue or PyObject_Not. These will call the __bool__ (and __len__) method or the C equivalents. bool() also uses the same special methods but besides checking for the truth value it will explicitly return a boolean object. So when you have if bool(...) you actually call (...).__bool__().__bool__() and with if ... you call (...).__bool__(). That's not 100% correct because we're dealing with C functions and types.Paradis
K
1

In python most (all?) objects have a bool value. The meaning behind "has a truth value of True" means that bool(obj) evaluates to True.

On the other hand, True is treated as 1 in many cases (and False as 0) which you can see when you do stuff like:

sum([True, True, False])
# (1 + 1 + 0) -> 2

That is why you get 1 == True --> True

There is a more explicit explanation in the documentation:

Boolean values are the two constant objects False and True. They are used to represent truth values (although other values can also be considered false or true). In numeric contexts (for example when used as the argument to an arithmetic operator), they behave like the integers 0 and 1, respectively

From the type-hierarchy itself in the docs:

These represent the truth values False and True. The two objects representing the values False and True are the only Boolean objects. The Boolean type is a subtype of the integer type, and Boolean values behave like the values 0 and 1, respectively, in almost all contexts, the exception being that when converted to a string, the strings "False" or "True" are returned, respectively.

Keeney answered 11/5, 2017 at 14:54 Comment(0)
H
1

I believe it's 1 == True here is that's weird, not that ... != True.

1 equals with True because in Python booleans are subclass of integers (because of PEP-285). See yourself:

>>> issubclass(bool, int)
True
Hooge answered 11/5, 2017 at 15:1 Comment(2)
Just a minor point: hashes don't matter when testing for equality (except in dict and set).Paradis
Ah, right. I thought still matters a little because of CPython treats small_ints (-5...+257) specially, always allocating the same instance, but it seems that 1 is not TrueHooge

© 2022 - 2024 — McMap. All rights reserved.