The reason that you are losing boolean values from a set
if they already contain 0
or 1
is because the following behavior...
>>> 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:
>>> 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 = 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:
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.