How come I can add the boolean value False but not True in a set in Python?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP


How come I can add the boolean value False but not True in a set in Python?



I just started investigating the set data type in Python. For some reason, whenever I add the Boolean value of True to a set it doesn't appear. However, if I add False to a set it will become an element of the set. I was shocked when I googled this question that nothing came up.


example1 = {1, 2, 7, False}
example2 = {7, 2, 4, 1, True}

print(example1)
print(example2)



The output is:


{False, 1, 2, 7}
{1, 2, 4, 7}





If true is 1 and false is 0, true is already in the set so it won't be added again.
– daniu
yesterday


true


false





print({0, False})
– DeepSpace
yesterday


print({0, False})





My Python 3.5.1 says {True, 2, 4, 7} and the 1 is gone. Python is sometimes unpythonic
– Thomas Weller
yesterday


{True, 2, 4, 7}





@ThomasWeller Considering that __future__ is still growing, it looks like Python 4 is going to be like Python 3 was to Python 2.
– wizzwizz4
yesterday


__future__





@ThomasWeller id(1) == id(True) gives False. They're different objects, despite being equal and having the same hash. True is an instance of bool, and 1 is an instance of int, which is a parent class of bool. == is not an identity comparison. The answer here is don't stuff bool and int in the same set. Why would you mix them?
– jpmc26
23 hours ago




id(1) == id(True)


False


True


bool


1


int


bool


==


bool


int




3 Answers
3



Because in Python 1 == True and you have 1 in your set already.


1 == True



Imagine this example:


example1 = {0, False, None}
example2 = {1, True}

print(example1)
print(example2)



Will output:


{0, None}
{1}



First set has 0 and None because 0 == False but 0 != None. With second set 1 == True so True isn't added to the set.


0


None


0 == False


0 != None


1 == True


True





Please note, while 1 == True is Python, but 1 is not True - the thing is hash(1) == hash(True) and that is the reason in {1, True} , value 1 is over-written by value True and in {True, 1} value True over-written by value True
– Grijesh Chauhan
16 hours ago




1 == True


1 is not True


hash(1) == hash(True)


{1, True}


1


True


{True, 1}


True


True



False and True are equal to 0 and 1, respectively. They are distinct entities, yet the two equal values cannot both be in a set. This is clearly undesired behavior, yet it is not clear it can be fixed and still allow multiplying by a boolean value to work as documented.


IPython 6.2.1 -- An enhanced Interactive Python.

1 is True
Out[1]: False

{1,True}
Out[2]: {1}

{0,False}
Out[3]: {0}

{False, 0}
Out[4]: {False}

{True, 1}
Out[5]: {True}



Notice that depending on the order of putting them into the set, 1 will not be in the set if True is already in it, and True will not be in the set if 1 is already in it.



The reason that you are losing boolean values from a set if they already contain 0 or 1 is because the following behavior...


set


0


1


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



...is guaranteed in Python 3.x.



Which means that you cannot have both in a set:


>>> set([True, 1])
{True}
>>> set([False, 0])
{False}



The hashes being equal is just as important as the objects being equal, because objects that are "equal" can produce different hashes and vice versa:


class Foo:
def __init__(self, x):
self.x = x
def __hash__(self):
return 1
def __eq__(self, other):
return self.x == other.x

class Bar:
def __init__(self, x):
self.x = x
def __hash__(self):
return 2
def __eq__(self, other):
return self.x == other.x

>>> x = Foo(3)
>>> y = Bar(3)
>>> x == y
True
>>> hash(x) == hash(y)
False
>>> set([x, y])
{<__main__.Bar at 0x56ed278>, <__main__.Foo at 0x5707390>}



You can also have a set that contains items with the same hashes, if those items are not equal:


set


>>> hash('a')
-904409032991049157
>>> hash(-904409032991049157)
-904409032991049157
>>> hash('a') == hash(-904409032991049157)
True
>>> set(['a', -904409032991049157])
{-904409032991049157, 'a'}



This behavior is not guaranteed in Python 2.x, for the simple reason that True and False are not reserved keywords (this change was introduced in 3.x). You may reassign them (although better not to), so there is no reason that the same behavior must hold in Python 2.x:


True


False


>>> True = 5
>>> hash(True) == hash(1)
False
>>> set([1, True])
set([1, 5])



But don't let the fact that True was replaced with 5 discourage you! We can abuse the representation of a class to make it appear as though True really is in the set.


True


5


True


class Foo(object):
def __repr__(self):
return('True')

>>> True = Foo()
>>> set([1, True])
set([1, True])



Obviously the last couple code snippets are bad practice, and are only for demonstration. The main takeaway is that equal objects with the same hash cannot be contained in the same set, and in Python 3.x, 1 and True, and 0 and False, will always have the same hash, and will always be equal.


set


1


True


0


False






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Stripe::AuthenticationError No API key provided. Set your API key using “Stripe.api_key = ”

CRM reporting Extension - SSRS instance is blank

Keycloak server returning user_not_found error when user is already imported with LDAP