<div dir="auto">I strongly agree with Ka-Ping. '+' is intuitively concatenation not merging. The behavior is overwhelmingly more similar to the '|' operator in sets (whether or not a user happens to know the historical implementation overlap).<div dir="auto"><br></div><div dir="auto">I think growing the full collection of set operations world be a pleasant addition to dicts. I think shoe-horning in plus would always be jarring to me.</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Mar 6, 2019, 5:30 AM Ka-Ping Yee <<a href="mailto:zestyping@gmail.com">zestyping@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div dir="ltr"><div>len(dict1 + dict2) does not equal len(dict1) + len(dict2), so using the + operator is nonsense.</div><div><br></div><div>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.</div><div><br></div><div>The operators should be |, &, and -, exactly as for sets, and the behaviour defined with just three rules:</div><div><br></div><div>1. The keys of dict1 [op] dict2 are the elements of dict1.keys() [op] dict2.keys().</div><div><br></div><div>2. The values of dict2 take priority over the values of dict1.</div><div><br></div><div>3. When either operand is a set, it is treated as a dict whose values are None.</div><div><br></div><div>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 |".</div><div><br></div><div>merge and update some items:</div><div><br></div><div>    {'a': 1, 'b': 2} | {'b': 3, 'c': 4} => {'a': 1, 'b': 3, 'c': 4}</div><div><br></div><div>pick some items:</div><div><br></div><div>    {'a': 1, 'b': 2} & {'b': 3, 'c': 4} => {'b': 3}</div><div><br></div><div>remove some items:</div><div><br></div><div>    {'a': 1, 'b': 2} - {'b': 3, 'c': 4} => {'a': 1}</div><div><br></div><div>reset values of some keys:</div><div><br></div><div>    {'a': 1, 'b': 2} | {'b', 'c'} => {'a': 1, 'b': None, 'c': None}</div><div><br></div><div>ensure certain keys are present:</div><div><br></div><div>    {'b', 'c'} | {'a': 1, 'b': 2} => {'a': 1, 'b': 2, 'c': None}</div><div><br></div><div>pick some items:</div><div><br></div><div>    {'b', 'c'} | {'a': 1, 'b': 2} => {'b': 2}</div><div><br></div><div>remove some items:</div><div><br></div><div>    {'a': 1, 'b': 2} - {'b', 'c'} => {'a': 1}</div></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Mar 6, 2019 at 1:51 AM Rémi Lapeyre <<a href="mailto:remi.lapeyre@henki.fr" target="_blank" rel="noreferrer">remi.lapeyre@henki.fr</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Le 6 mars 2019 à 10:26:15, Brice Parent<br>
(<a href="mailto:contact@brice.xyz" target="_blank" rel="noreferrer">contact@brice.xyz</a>(mailto:<a href="mailto:contact@brice.xyz" target="_blank" rel="noreferrer">contact@brice.xyz</a>)) a écrit:<br>
<br>
><br>
> Le 05/03/2019 à 23:40, Greg Ewing a écrit :<br>
> > Steven D'Aprano wrote:<br>
> >> The question is, is [recursive merge] behaviour useful enough and<br>
> > > common enough to be built into dict itself?<br>
> ><br>
> > I think not. It seems like just one possible way of merging<br>
> > values out of many. I think it would be better to provide<br>
> > a merge function or method that lets you specify a function<br>
> > for merging values.<br>
> ><br>
> That's what this conversation led me to. I'm not against the addition<br>
> for the most general usage (and current PEP's describes the behaviour I<br>
> would expect before reading the doc), but for all other more specific<br>
> usages, where we intend any special or not-so-common behaviour, I'd go<br>
> with modifying Dict.update like this:<br>
><br>
> foo.update(bar, on_collision=updator) # Although I'm not a fan of the<br>
> keyword I used<br>
<br>
Le 6 mars 2019 à 10:26:15, Brice Parent<br>
(<a href="mailto:contact@brice.xyz" target="_blank" rel="noreferrer">contact@brice.xyz</a>(mailto:<a href="mailto:contact@brice.xyz" target="_blank" rel="noreferrer">contact@brice.xyz</a>)) a écrit:<br>
<br>
><br>
> Le 05/03/2019 à 23:40, Greg Ewing a écrit :<br>
> > Steven D'Aprano wrote:<br>
> >> The question is, is [recursive merge] behaviour useful enough and<br>
> > > common enough to be built into dict itself?<br>
> ><br>
> > I think not. It seems like just one possible way of merging<br>
> > values out of many. I think it would be better to provide<br>
> > a merge function or method that lets you specify a function<br>
> > for merging values.<br>
> ><br>
> That's what this conversation led me to. I'm not against the addition<br>
> for the most general usage (and current PEP's describes the behaviour I<br>
> would expect before reading the doc), but for all other more specific<br>
> usages, where we intend any special or not-so-common behaviour, I'd go<br>
> with modifying Dict.update like this:<br>
><br>
> foo.update(bar, on_collision=updator) # Although I'm not a fan of the<br>
> keyword I used<br>
<br>
This won’t be possible update() already takes keyword arguments:<br>
<br>
>>> foo = {}<br>
>>> bar = {'a': 1}<br>
>>> foo.update(bar, on_collision=lambda e: e)<br>
>>> foo<br>
{'a': 1, 'on_collision': <function <lambda> at 0x10b8df598>}<br>
<br>
> `updator` being a simple function like this one:<br>
><br>
> def updator(updated, updator, key) -> Any:<br>
> if key == "related":<br>
> return updated[key].update(updator[key])<br>
><br>
> if key == "tags":<br>
> return updated[key] + updator[key]<br>
><br>
> if key in ["a", "b", "c"]: # Those<br>
> return updated[key]<br>
><br>
> return updator[key]<br>
><br>
> There's nothing here that couldn't be made today by using a custom<br>
> update function, but leaving the burden of checking for values that are<br>
> in both and actually inserting the new values to Python's language, and<br>
> keeping on our side only the parts that are specific to our use case,<br>
> makes in my opinion the code more readable, with fewer possible bugs and<br>
> possibly better optimization.<br>
><br>
><br>
> _______________________________________________<br>
> Python-ideas mailing list<br>
> <a href="mailto:Python-ideas@python.org" target="_blank" rel="noreferrer">Python-ideas@python.org</a><br>
> <a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
> Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
_______________________________________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org" target="_blank" rel="noreferrer">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
</blockquote></div>
_______________________________________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org" target="_blank" rel="noreferrer">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
</blockquote></div>