[Python-ideas] Adding "+" and "+=" operators to dict
Steven D'Aprano
steve at pearwood.info
Thu Feb 12 11:43:10 CET 2015
On Thu, Feb 12, 2015 at 01:07:52AM -0800, Ian Lee wrote:
> Alright, I've tried to gather up all of the feedback and organize it in
> something approaching the alpha draft of a PEP might look like::
>
>
> Proposed New Methods on dict
> ============================
>
> Adds two dicts together, returning a new object with the type of the left
> hand operand. This would be roughly equivalent to calling:
>
> >>> new_dict = old_dict.copy();
> >>> new_dict.update(other_dict)
A very strong -1 on the proposal. We already have a perfectly good way
to spell dict += , namely dict.update. As for dict + on its own, we have
a way to spell that too: exactly as you write above.
I think this is a feature that is more useful in theory than in
practice. Which we already have a way to do a merge in place, and a
copy-and-merge seems like it should be useful but I'm struggling to
think of any use-cases for it. I've never needed this, and I've never
seen anyone ask how to do this on the tutor or python-list mailing
lists.
I certainly wouldn't want to write
new_dict = a + b + c + d
and have O(N**2) performance when I can do this instead
new_dict = {}
for old_dict in (a, b, c, d):
new_dict.update(old_dict)
and have O(N) performance. It's easy to wrap this in a small utility
function if you need to do it repeatedly.
There was an earlier proposal to add an updated() built-in, by analogy
with list.sort/sorted, there would be dict.update/updated. Here's the
version I have in my personal toolbox (feel free to use it, or not, as
you see fit):
def updated(base, *mappings, **kw):
"""Return a new dict from one or more mappings and keyword arguments.
The dict is initialised from the first argument, which must be a mapping
that supports copy() and update() methods. The dict is then updated
from any subsequent positional arguments, from left to right, followed
by any keyword arguments.
>>> d = updated({'a': 1}, {'b': 2}, [('a', 100), ('c', 200)], c=3)
>>> d == {'a': 100, 'b': 2, 'c': 3}
True
"""
new = base.copy()
for mapping in mappings + (kw,):
new.update(mapping)
return new
although as I said, I've never needed to use it in 15+ years. Someday,
perhaps... Note that because this is built on the update method, it
supports sequences of (key,value) tuples, and additional keyword
arguments, which a binary operator cannot do.
I would give a +0.5 on a proposal to add an updated() builtin: I doubt
that it will be used often, but perhaps it will come in handy from time
to time. As the experience with list.sort versus sorted() shows, making
one a method and one a function helps avoid confusion. The risk of
confusion makes me less enthusiastic about adding a dict.updated()
method: only +0 for that.
I dislike the use of + for concatenation, but can live with it. This
operation, however, is not concatenation, nor is it addition. I am
strongly -1 on the + operator, and -0.75 on | operator.
--
Steve
More information about the Python-ideas
mailing list