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

Multi tool use


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}
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.
If
true
is 1 andfalse
is 0, true is already in the set so it won't be added again.– daniu
yesterday