Python 3.9 dict union op: keys at odds with values

Some readers on r/python didn’t get the corner case I point out so I wrote the following:

Given:

k1, v1 = int(1), "x" 
k2, v2 = float(k1), v1 * 3

In Python 3.9 what does this evaluate to

{k1: v1} | {k2: v2}
  • Is the key of the result k1 or k2?
  • Is the value of the result v1 or v2?

Specifically, hash(1) (int) and hash(1.0) (float) are the same (don’t have to be equal)

You can simplify the example:

>>> {1: "x"} | {1.0: "xxx"}
{1: 'xxx'}
1 Like

Nice simplification. …That still shows that the first of the equal-by-hash keys and/but the last of the values is used. I thought this first/last thing was noteworthy in this corner case.

You can also ask “what would dict.update() do?”

>>> d1 = {int(1): "a"}
>>> d2 = {float(1): "aaa"}
>>> d1.update(d2)
>>> d1
{1: 'aaa'}

The merge operator | and in-place update operator |= emulate the update method.

>>> d1 = {int(1): "a"}
>>> d1 | d2
{1: 'aaa'}

Hopefully what you’ve found agrees with traditional dict.update() behavior.

2 Likes

It can be even simpler:

>>> {1: 'foo', 1.0: 'bar'}
{1: 'bar'}

The explanation is, that 1 and 1.0 are “the same value”, i.e. they have the same hash value and compare equal.

This means that 1.0: 'bar' updates the existing entry, but because “it is the same key”, the key doesn’t get updated, only the value does.

1 Like