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).
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. On Wed, Mar 6, 2019, 5:30 AM Ka-Ping Yee <zestyp...@gmail.com> wrote: > 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.lape...@henki.fr> wrote: > >> Le 6 mars 2019 à 10:26:15, Brice Parent >> (cont...@brice.xyz(mailto:cont...@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 >> (cont...@brice.xyz(mailto:cont...@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@python.org >> > https://mail.python.org/mailman/listinfo/python-ideas >> > Code of Conduct: http://python.org/psf/codeofconduct/ >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas@python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > _______________________________________________ > Python-ideas mailing list > Python-ideas@python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ >
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/