I created the following dictionary
exDict = {True: 0, False: 1, 1: \'a\', 2: \'b\'}
and when I print exDict.keys()
, well, it g
What you are seeing is python coercing the 1
to be equal to the True
.
You'll see that the dictionary you print is:
False 1
True a
2 b
Where the value a
was meant to be assigned to the 1
, but instead the value for True
got reassigned to a
.
According to the Python 3 Documentation:
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.
Emphasis mine.
Note: In python 2.X True
and False
can be re-assigned, so this behavior cannot be guaranteed.
This happens because True == 1
(and False == 0
, but you didn't have 0
as a key). You'll have to refactor your code or data somehow, because a dict
considers keys to be the same if they are "equal" (rather than is
).
Python take the 1 as True
. And the Boolean type is a subtype of the integer type
In [1]: a = {}
In [2]: a[True] = 0
In [3]: 1 in a.keys()
Out[3]: True
If you insert a key-value pair in a dict
python checks if the key already exists and if it exists it will replace the current value.
This check does something like this:
def hash_and_value_equal(key1, key2):
return hash(key1) == hash(key2) and key1 == key2
So not only must the values be equal but also their hash
. Unfortunatly for you True
and 1
but also False
and 0
will be considered equal keys:
>>> hash_and_value_equal(0, False)
True
>>> hash_and_value_equal(1, True)
True
and therefore they replace the value (but not the key):
>>> a = {1: 0}
>>> a[True] = 2
>>> a
{1: 2}
>>> a = {False: 0}
>>> a[0] = 2
>>> a
{False: 2}
I've showed the case of adding a key manually but the steps taken are the same when using the dict literal
:
>>> a = {False: 0, 0: 2}
>>> a
{False: 2}
or the dict
-builtin:
>>> a = dict(((0, 0), (False, 2)))
>>> a
{0: 2}
This can be very important if you write own classes and want to use them as potential keys inside dictionaries. Depending on your implementation of __eq__
and __hash__
these will and won't replace the values of equal but not identical keys:
class IntContainer(object):
def __init__(self, value):
self.value = value
def __eq__(self, other):
return self.value == other
def __hash__(self):
# Just offsetting the hash is enough because it also checks equality
return hash(1 + self.value)
>>> hash_equal(1, IntContainer(1))
False
>>> hash_equal(2, IntContainer(1))
False
So these won't replace existing integer keys:
>>> a = {1: 2, IntContainer(1): 3, 2: 4}
>>> a
{1: 2, <__main__.IntContainer at 0x1ee1258fe80>: 3, 2: 4}
or something that is considered as identical key:
class AnotherIntContainer(IntContainer):
def __hash__(self):
# Not offsetted hash (collides with integer)
return hash(self.value)
>>> hash_and_value_equal(1, AnotherIntContainer(1))
True
These will now replace the integer keys:
>>> a = {1: 2, AnotherIntContainer(1): 5}
>>> a
{1: 5}
The only really important thing is to keep in mind that dictionary keys are consered equal if the objects and their hash is equal.