Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding 1 to a set containing True does not work

I have recently started to learn Python and have encountered something a little strange when playing with sets. The following code sample doesn't produce the expected results.

a_set = {True,2,3,4}
a_set.add(1)

I expected a_set to have the values {True, 1, 2, 3, 4} but instead this code produced {True, 2, 3, 4}.

Trying variations on this also produced the same results:

a_set = {1,2,3,4}
a_set.add(True)

Expected {True, 1, 2, 3, 4} Actual {1, 2, 3, 4}

Trying this with False and 0 obtained the same results:

a_set = {False,2,3,4}
a_set.add(0)

Expected {False, 0, 2, 3, 4} Actual {False, 2, 3, 4}

a_set = {0,2,3,4}
a_set.add(False)

Expected {False, 0, 2, 3, 4} Actual {0, 2, 3, 4}

I understand that the bool type is inherited from int and that True == 1 and False == 0 but was still a little surprised by the above results.

Does anybody know if this behaviour is by design? Also is it possible to have a set which contains both True, False, 0, and 1?

I did perform quite a bit of googling but was not able to find an answer to my questions.

Thanks in advance

UPDATE

In response to the comments below I agree that the following question partially answers my question.

Is False == 0 and True == 1 in Python an implementation detail or is it guaranteed by the language?

But I feel that it doesn't answer the query I have regarding the behaviour of sets and whether it is possible to have a set containing both True and 1. Even though bool is inherited from int, they are different types, so I found the fact that a set cannot distinguish between True and 1 to be a little confusing. So really this is a question about the behaviour of sets in Python not just about True == 1.

like image 478
mickfold Avatar asked Aug 15 '13 17:08

mickfold


1 Answers

For historical (hysterical?) reasons Python's bool type is a subclass of int, and True is equal to 1 and False is equal to 0.

They hash to the same location as well:

>>> True == 1
True
>>> hash(True) == hash(1)
True
>>> False == 0
True
>>> hash(False) == hash(0)
True

Since both True and 1 are considered equal and they hash to the same slot, both set and dict treat them as the same thing.

You'll see the same with a dictionary:

>>> True in {1: 'foo'}
True
>>> 1 in {True: 'foo'}
True

This behaviour extends to other numbers too; floating point values equal to integer values will show the same behaviour:

>>> {1.0, 1, 2.0, 2}
{1, 2}

but at least the reasons why that happens are a little more.. obvious.

like image 157
Martijn Pieters Avatar answered Sep 21 '22 12:09

Martijn Pieters