[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