It operates similarly to bitwise or, combining all the set bits, or like the or operator on sets, combining all the set elements. "|" has never meant logical or in python nor in most other common programming languages.
[Edit: I thought the parent comment was saying that they were expecting dict1 | dict2 to equal either dict1 or dict2, not some combination of them. Instead, they were referring to the which value gets chosen if the same key is in both dictionaries. Thanks to minitech for their comment that helped me see what they were saying.]
Are you also surprised when the original bitwise meaning of "|" does not return either of the two arguments?
Bitwise or works at the level of bits, so the question is more like, in:
>>> bin(0b011 | 0b010)
'0b11'
Does the leading 1 come from the first argument or the second argument? It isn't really a sensible question for bits, since the 1s are indistinguishable. However the values in the hash table are distinguishable, so it's a valid question.
Also, taking an example from another comment:
>>> {0} | {False}
{0}
>>> {False} | {0}
{False}
This is another example where the union operator is used, but here it picks the first value, rather than the second value.
Gotta say though that I intuitivly think of the dict union operator x | y as {* * x, * * y}. Which is how I would have joined two dictionaries before, when I wanted to produce a complete copy of one, i.e. not use dict.update.
If you read the dict union operator "|" as something similar to "or", (like me), you are in for a surprise:
>>> x = {"key1": "value1 from x", "key2": "value2 from x"}
>>> y = {"key2": "value2 from y", "key3": "value3 from y"}
>>> x | y
{'key1': 'value1 from x', 'key2': 'value2 from y', 'key3': 'value3 from y'}
What I expect is
>>> x | y
{"key1": "value1 from x", "key2": "value2 from x", "key3": "value3 from y"}