[Python-ideas] Dict joining using + and +=

Davide Rizzo sorcio at gmail.com
Fri Mar 8 08:06:37 EST 2019


> Counter also uses +/__add__ for a similar behavior.
>
>     >>> c = Counter(a=3, b=1)
>     >>> d = Counter(a=1, b=2)
>     >>> c + d # add two counters together:  c[x] + d[x]
>     Counter({'a': 4, 'b': 3})
>
> At first I worried that changing base dict would cause confusion for the subclass, but Counter seems to share the idea that update and + are synonyms.

Counter is a moot analogy. Counter's + and - operators follow the
rules of numbers addition and subtraction:

>>> c = Counter({"a": 1})
>>> c + Counter({"a": 5})
Counter({'a': 6})
>>> c + Counter({"a": 5}) - Counter({"a": 4})
Counter({'a': 2})

Which also means that in most cases (c1 + c2) - c2 == c1 which is not
something you would expect with the suggested "dictionary addition"
operation. As a side note, this is not true in general for Counters
because of how subtraction handles 0. E.g.

>>> c0 = Counter({"a": 0})
>>> c1 = Counter({"a": 1})
>>> (c0 + c1) - c1
Counter()
>>> (c0 + c1) - c1 == c0
False

---

The current intuition of how + and - work don't apply literally to
this suggestion:

1) numeric types are their own story
2) most built-in sequences imply concatenation for + and have no subtraction
3) numpy-like arrays behave closer to numbers
4) Counters mimic numbers in some ways and while addition reminds of
concatenation (but order is not relevant) they also have subtraction
5) sets have difference which is probably the closest you expect from
dict subtraction, but no + operator

---

I understand the arguments against a | operator for dicts but I don't
entirely agree with them. dict is obviously a different type of object
than all the others I've mentioned, even mathematically, and there is
no clear precedent. If sets happened to maintain insertion order, like
dicts after 3.6/3.7, I would expect the union operator to also
preserve the order. Before 3.6 we probably would have seen dicts as
closer to sets from that point of view, and this suggested addition as
closer to set union.

The question of symmetry ({"a": 1} + {"a": 2}) is an important one and
I would consider not enforcing one resolution in PEP 584, and instead
leave this undefined (i.e. in the resulting dict, the value could be
either 1 or 2, or just completely undefined to also be compatible with
Counter-like semantics in the same PEP). This is something to consider
carefully if the plan is to make the new operators part of Mapping.
It's not obvious that all mappings should implement this the same way,
and a survey of what is being done by other implementation of Mappings
would be useful. On the other hand leaving it undefined might make it
harder to standardize it later, once other implementations have
defined their own behavior.

This question is probably on its own a valid argument against the
proposal. When it comes to dicts (and not Mappings in general) {**d1,
**d2} or d.update() already have clearly-defined semantics. The new
proposal for a merge() operation might be more useful. The added value
would be the ability to add two mappings regardless of concrete type.
But it's with Mappings in general that this proposal is the most
problematic.

On the other hand the subtraction operator is probably less
controversial and immediately useful (the idiom to remove keys from a
dictionary is not obvious).


More information about the Python-ideas mailing list