[Python-ideas] PEP: Dict addition and subtraction

Ka-Ping Yee zestyping at gmail.com
Wed Mar 6 05:29:27 EST 2019


len(dict1 + dict2) does not equal len(dict1) + len(dict2), so using the +
operator is nonsense.

len(dict1 + dict2) cannot even be computed by any expression involving +.
Using len() to test the semantics of the operation is not arbitrary; the
fact that the sizes do not add is a defining quality of a merge.  This is a
merge, not an addition.  The proper analogy is to sets, not lists.

The operators should be |, &, and -, exactly as for sets, and the behaviour
defined with just three rules:

1. The keys of dict1 [op] dict2 are the elements of dict1.keys() [op]
dict2.keys().

2. The values of dict2 take priority over the values of dict1.

3. When either operand is a set, it is treated as a dict whose values are
None.

This yields many useful operations and, most importantly, is simple to
explain.  "sets and dicts can |, &, -" takes up less space in your brain
than "sets can |, &, - but dicts can only + and -, where dict + is like set
|".

merge and update some items:

    {'a': 1, 'b': 2} | {'b': 3, 'c': 4} => {'a': 1, 'b': 3, 'c': 4}

pick some items:

    {'a': 1, 'b': 2} & {'b': 3, 'c': 4} => {'b': 3}

remove some items:

    {'a': 1, 'b': 2} - {'b': 3, 'c': 4} => {'a': 1}

reset values of some keys:

    {'a': 1, 'b': 2} | {'b', 'c'} => {'a': 1, 'b': None, 'c': None}

ensure certain keys are present:

    {'b', 'c'} | {'a': 1, 'b': 2} => {'a': 1, 'b': 2, 'c': None}

pick some items:

    {'b', 'c'} | {'a': 1, 'b': 2} => {'b': 2}

remove some items:

    {'a': 1, 'b': 2} - {'b', 'c'} => {'a': 1}

On Wed, Mar 6, 2019 at 1:51 AM Rémi Lapeyre <remi.lapeyre at henki.fr> wrote:

> Le 6 mars 2019 à 10:26:15, Brice Parent
> (contact at brice.xyz(mailto:contact at brice.xyz)) a écrit:
>
> >
> > Le 05/03/2019 à 23:40, Greg Ewing a écrit :
> > > Steven D'Aprano wrote:
> > >> The question is, is [recursive merge] behaviour useful enough and
> > > > common enough to be built into dict itself?
> > >
> > > I think not. It seems like just one possible way of merging
> > > values out of many. I think it would be better to provide
> > > a merge function or method that lets you specify a function
> > > for merging values.
> > >
> > That's what this conversation led me to. I'm not against the addition
> > for the most general usage (and current PEP's describes the behaviour I
> > would expect before reading the doc), but for all other more specific
> > usages, where we intend any special or not-so-common behaviour, I'd go
> > with modifying Dict.update like this:
> >
> > foo.update(bar, on_collision=updator) # Although I'm not a fan of the
> > keyword I used
>
> Le 6 mars 2019 à 10:26:15, Brice Parent
> (contact at brice.xyz(mailto:contact at brice.xyz)) a écrit:
>
> >
> > Le 05/03/2019 à 23:40, Greg Ewing a écrit :
> > > Steven D'Aprano wrote:
> > >> The question is, is [recursive merge] behaviour useful enough and
> > > > common enough to be built into dict itself?
> > >
> > > I think not. It seems like just one possible way of merging
> > > values out of many. I think it would be better to provide
> > > a merge function or method that lets you specify a function
> > > for merging values.
> > >
> > That's what this conversation led me to. I'm not against the addition
> > for the most general usage (and current PEP's describes the behaviour I
> > would expect before reading the doc), but for all other more specific
> > usages, where we intend any special or not-so-common behaviour, I'd go
> > with modifying Dict.update like this:
> >
> > foo.update(bar, on_collision=updator) # Although I'm not a fan of the
> > keyword I used
>
> This won’t be possible update() already takes keyword arguments:
>
> >>> foo = {}
> >>> bar = {'a': 1}
> >>> foo.update(bar, on_collision=lambda e: e)
> >>> foo
> {'a': 1, 'on_collision': <function <lambda> at 0x10b8df598>}
>
> > `updator` being a simple function like this one:
> >
> > def updator(updated, updator, key) -> Any:
> > if key == "related":
> > return updated[key].update(updator[key])
> >
> > if key == "tags":
> > return updated[key] + updator[key]
> >
> > if key in ["a", "b", "c"]: # Those
> > return updated[key]
> >
> > return updator[key]
> >
> > There's nothing here that couldn't be made today by using a custom
> > update function, but leaving the burden of checking for values that are
> > in both and actually inserting the new values to Python's language, and
> > keeping on our side only the parts that are specific to our use case,
> > makes in my opinion the code more readable, with fewer possible bugs and
> > possibly better optimization.
> >
> >
> > _______________________________________________
> > 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/
> _______________________________________________
> 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/20190306/6e33ede6/attachment.html>


More information about the Python-ideas mailing list