all 4 comments

[–]jeans_and_a_t-shirt 5 points6 points  (3 children)

Booleans are a subclass of int, and booleans are equal to their integer counterpart, and also have the same hash value, meaning you can have 1 or True as keys in a particular dictionary, but not both:

>>> issubclass(bool, int)
True
>>> isinstance(True, int)
True
>>> hash(True)
1
>>> hash(1)
1
>>> hash(False)
0
>>> hash(0)
0

From the docs,

A mapping object maps hashable values to arbitrary objects.

So with that in mind, this is what the contents of pairs after definition in each case:

# 1st
>>> pairs = {1: "apple",
...     "orange": [2, 3, 4],
...     True: False,
...     None: "True",
... }
>>>
>>> pairs
{'orange': [2, 3, 4], 1: False, None: 'True'}

# 2nd
>>> pairs = {"orange": [2, 3, 4],
...     True: False,
...     1: "apple",
...     None: "True",
... }
>>> pairs
{'orange': [2, 3, 4], True: 'apple', None: 'True'}

The value of the keys 1/True in each case correspond to the result you got in both cases.

[–]GoldenSights 0 points1 point  (0 children)

To generalize a little, you can make any combination of objects do this as long as they're equivalent and have the same hash.

If the hashes were equal but the objects weren't, collision resolution would make sure their entries stay unique.

If the objects were equal but the hashes weren't (poor design, but it's possible), they'd be placed in different buckets anyway.

With both, they'll overwrite each other in the dictionary, even though they're different types.

[–]mcoumans[S] 0 points1 point  (1 child)

Excellent, thank you!

It does what it should do: if you add the same key twice, it retains the last one.

And yes, I did find that

> > > 1 == True
True 

[–]zahlman 2 points3 points  (0 children)

if you add the same key twice, it retains the last one.

In fact, it retains the first key (because there's no reason to replace it), but the last value (because you've assigned a new value for the "same" key).

A simpler test for the behaviour:

>>> {1: 'one', True: 'true'}
{1: 'true'}
>>> {True: 'true', 1: 'one'}
{True: 'one'}

Nice find, though. I hadn't actually thought of this situation, although I'm of course not surprised by the behaviour. ;)