[Python-ideas] Adding "+" and "+=" operators to dict

Ian Lee ianlee1521 at gmail.com
Thu Feb 12 10:07:52 CET 2015


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)

Where ``new_dict`` is the same type as ``old_dict``, but possibly not the
same
as ``other_dict``.

__add__
-------

    >>> foo = {'a': 1, 'b': 'xyz'}
    >>> bar = {'a': 5.0, 'c': object()}
    >>> baz = foo + bar
    >>> foo
    {'a': 1, 'b': 'xyz'}
    >>> bar
    {'a': 5.0, 'c': object()}
    >> baz
    {'a': 5.0, 'b': 'xyz', 'c': object()}

__iadd__
--------

    >>> foo = {'a': 1, 'b': 'xyz'}
    >>> bar = {'a': 5.0, 'c': object()}
    >>> foo += bar
    >>> foo
    {'a': 5.0, 'b': 'xyz', 'c': object()}
    >>> bar
    {'a': 5.0, 'c': object()}

__radd__
--------

The reverse add was mentioned in [2], [5]. I'm not sure I have the following
example exactly right, particularly the type. My initial thought is to have
it
come out as the type of the left hand operand. So, assuming LegacyMap has no
``__add__`` method:

    >>> foo = LegacyMap{'a': 1, 'b': 'xyz'}
    >>> bar = dict({'a': 5.0, 'c': object()})
    >>> baz = foo + bar  # e.g. bar.__radd__(foo)
    >>> baz
    {'a': 5.0, 'b': 'xyz', 'c': object()}
    >>> type(baz) == LegacyMap


Considerations
==============

Key Collisions
--------------

When there is a key collision, handle as currently by ``dict.update()``,
namely
that the right hand operand "wins".

Adding mappings of different types
----------------------------------

Here is what currently happens in a few cases in Python 3.4, given:

    >>> class A(dict): pass
    >>> class B(dict): pass
    >>> foo = A({'a': 1, 'b': 'xyz'})
    >>> bar = B({'a': 5.0, 'c': object()})

Currently (this surprised me actually... I guess it gets the parent class?):

    >>> baz = foo.copy()
    >>> type(baz)
    dict

Currently:

    >>> foo.update(bar)
    >>> foo
    >>> type(foo)
    A

Idea about '+' adding values
----------------------------

The idea of ``{'x': 1} + {'x': 2} == {'x': 3}`` was mentioned [3], [4] and
seems to
not have had a lot of support. In particular, this goes against the current
usage of the ``dict.update()`` method, where:

    >>> d = {'x': 1}
    >>> d.update({'x': 2})
    >>> d
    {'x': 2}

'+' vs '|' Operator
-------------------

If I was completely uninitiated, I would probably reach for the '+' first,
but
I don't feel this is the crux of the issue...

Backport to PyPI
----------------

> And whether it's worth writing a dict subclass that adds this method and
> putting it on PyPI as a backport (people writing 3.3+ code or 2.7/3.5 code
> can then just "from dict35 import dict35 as dict", but of course they
still
> won't be able to add two dicts constructed from literals).
-- Andrew Barnert [2]

Sure, I'd be willing to do this.

References
==========

[1] https://mail.python.org/pipermail/python-ideas/2014-July/028440.html
[2] https://mail.python.org/pipermail/python-ideas/2015-February/031755.html
[3] https://mail.python.org/pipermail/python-ideas/2015-February/031773.html
[4] https://mail.python.org/pipermail/python-ideas/2014-July/028425.html

Other Discussions
-----------------

As best I can, tell from reading through some of these threads there was
never
really a conclusion, and instead the discussions eventually fizzled out.

https://mail.python.org/pipermail/python-ideas/2014-July/028424.html
https://mail.python.org/pipermail/python-ideas/2011-December/013227.html
https://mail.python.org/pipermail/python-ideas/2013-June/021140.html



~ Ian Lee

On Thu, Feb 12, 2015 at 12:59 AM, Florian Bruhin <me at the-compiler.org>
wrote:

> * M.-A. Lemburg <mal at egenix.com> [2015-02-12 09:51:22 +0100]:
> > However, I don't really see the point in having an operation that
> > takes two dictionaries, creates a new empty one and updates this
> > with both sides of the operand. It may be theoretically useful,
> > but it results in the same poor performance you have in string
> > concatenation.
> >
> > In applications, you normally just need the update functionality
> > for dictionaries. If you do need a copy, you can create a copy
> > explicitly - but those cases are usually rare.
> >
> > So +1 on the '+=' syntax, -1 on '+' for dicts.
>
> I think it'd be rather confusing if += works but + does not.
>
> Regarding duplicate keys, IMHO only two options make sense:
>
> 1) Raise an exception
> 2) The right-hand side overrides keys in the left-hand side.
>
> I think #1 would prevent many useful cases where + could be used
> instead of .update(), so +1 for #2.
>
> Florian
>
> --
> http://www.the-compiler.org | me at the-compiler.org (Mail/XMPP)
>    GPG: 916E B0C8 FD55 A072 | http://the-compiler.org/pubkey.asc
>          I love long mails! | http://email.is-not-s.ms/
>
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20150212/330c07ab/attachment-0001.html>


More information about the Python-ideas mailing list