If I write:
d = { 0:'a', 1:'b' }
d[False] = 'c'
d[True] = 'd'
print(d)
I get:
{ 0:'c', 1:'d' }
Why is it coercing them into ints? It does the same thing in reverse.
d = {False:'a', True:'b'}
d[0] = 'c'
d[1] = 'd'
print(d)
Output is:
{False:'c', True: 'd'}
Can this be disabled? Is it a bug?
It's because those values are considered equal:
>>> True == 1
True
>>>
>>> False == 0
True
and have the same hash values:
>>> hash(True), hash(1)
(1, 1)
>>>
>>> hash(False), hash(0)
(0, 0)
Therefore, from the dictionary's point of view, True
and 1
are indistinguishable as are False
and 0
.
There is no way to "disable" this -- you shouldn't be using non-homogenous keys in a dict to begin with.
A potential workaround in this specific case would be to reserve special int values for True
and False
other than 1
and 0
, respectively (presuming you need 1
and 0
as independent keys). For instance, you could have -1
represent True
and -2
represent False
.
Just offering some background on arshajii's answer.
The two boolean values, True
and False
, have a strange relation with integers.
On one hand, they have different string representations, and have separate identities:
>>> print(True)
True
>>> print(1)
1
>>> True is 1
False
On the other hand, they behave as integers under comparisons and arithmetic:
>>> True == 1
True
>>> True + 1
2
The reason for this behavior is compatibility. A long time ago, the bool
type didn't exist. "Boolean" operators copied C behavior, reusing 0
and 1
for "false" and "true".
Eventually Guido realized this didn't make much sense, and added the constants we know and love.
But there was a problem. Even then, there was already a lot of code that treated boolean values like integers. If boolean operations started using the "correct" type, all this code would break.
So Guido made a compromise. Booleans have their own type, bool
, and display differently to integers. But in arithmetic operations and comparisons, most notably __eq__
and __hash__
, they are treated as one and the same. So old code would continue to work, while new code can still take advantage of the new bool
type.
Maybe that'll change in Python 4. But for now, bool
is a subclass of int
, and we'll have to live with that.
(On a related note, that's one of the reasons why True
and False
are in Title Case, rather than lower case like other Python keywords.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With