20 Oct
2019
20 Oct
'19
6:29 p.m.
Christopher Barker wrote: > On Sat, Oct 19, 2019 at 3:14 PM Dominik Vilsmeier dominik.vilsmeier@gmx.de > wrote: > > I like the proposal of adding an operator but I > > dislike the usage of "+". > > I'd expect this to do a recursive merge on the dict values for duplicate > > keys (i.e. adding the values), even more so since Counter (being a > > subclass of dict) already has that behavior. > > I think that's actually a counter argument (ha!) -- since there IS a > special "counter" type, why would anyone expect the regular dict to act > that way? The question is, why would someone who has experience with adding counters but never felt the need to add dicts, assume that this behavior is specialized in `Counter` and not inherited by `dict`. Maybe at some point they'll encounter a scenario where they need to recursive-merge (the `Counter` style) two dicts and then they might assume that they just need to add the dicts since they're familiar with this behavior from `Counter` and `Counter` subclasses `dict` so it's reasonable to assume this behavior is inherited. > Also, that behavior only makes sense for particular dicts -- it really is a > special case, perfect for a dict subclass (you know, maybe call it > Counter), but not for generic dict behavor. Maybe from a language design point of view, but a user might not be aware that this behavior is too specialized for generic dict. Besides `Counter`, `pandas` is another prominent example that uses the recursive merge strategy for mapping-like types (not necessarily in the collections.abc sense but exposing a similar interface): >>> s1 = pd.Series([[0, 1], 2]) >>> s2 = pd.Series([[3, 4], 5]) >>> s1 + s2 0 [0, 1, 3, 4] 1 7 Someone who is familiar with these types is probably used to that behavior and so it's easy to assume that it originates from dict. And even if they think it's too specialized, so `dict` must be doing something else, how obvious is the conclusion that dict performs a shallow merge and resolves conflicting keys by giving precedence to the r.h.s. operand? > > I think it would be helpful if the associated > > operator is not a symmetric > > symbol but instead is explicit about which operand takes precedence for > > conflicting keys. The lshift "<<" operator, for example, does have this > > property. It would be pretty clear what this means a << b: > > well, maybe. but I think there are two ways of thinking about "intuitive" > 1) if someone sees this code, will they be right in knowing what it means? > (Readability) > 2) if someone want to do something? Will they think to try this? > (Discoverability) > So << might be more intuitive from a readability perspective, but less > discoverable. > Note in this discussion (particularly the previous long one) that > apparently newbies often expect to be able to add dicts. > That being said, << or | is a lot better than adding yet another operator. I wasn't arguing particularly for the "<<" operator, I wanted to pointed out why, i.m.o., the "+" operator, as a symmetric symbol, isn't an ideal choice by comparing it to a non-symmetric operator symbol. I agree that "+" is likely more discoverable. Regarding intuition, as you pointed out, it's a two-way relationship: <operator> <--> <action>. So if someone wants to perform <action> it should be intuitive to think of <operator> (discoverability) and if someone reads <operator> it should be intuitive to associate it with <action> (readability, interpretability); I think "+" isn't very good at the latter. > > take the items of "b" and put them into "a" (or a > > copy thereof, > > overwriting what's already there) in order to create the result. The PEP > > mentions lack of interest in this operator though, as well as: > > The "cuteness" value of abusing the operator to > > indicate information > > flow got old shortly after C++ did it. > > I think a clear advantage of "<<" over "+" is that it indicates the > > direction (or precedence) which is important if items are potentially to be > > overwritten. I'd say "old but gold". > > In the section about Dict addition is > > lossy you > > write that "no other form of addition is lossy". This is true for the > > builtin types (except for floating point accuracy) but as part of the > > stdlib we have collections.deque which supports "+" and can be lossy if > > it specifies maxlen. For example: > > >>> d1 = deque([1, 2], maxlen=3) > > >>> d2 = deque([3, 4]) > > >>> d1 + d2 > > deque([2, 3, 4], maxlen=3) > > > > I think this is unfortunate especially since as a double ended queue it > > supports both extend and extendleft, so it's not clear whether > > this > > extends d1 by d2 or left-extends d2 by d1 (though the latter would probably > > be ambiguous about the order of items appended). Usage of d1 << d2 on > > the > > other hand would be explicit and clear about the direction of data flow. > > Although a bit different for dicts, it would as well indicate which of the > > operands takes precedence over the other. > > > > Python-ideas mailing list -- python-ideas@python.org > > To unsubscribe send an email to python-ideas-leave@python.org > > https://mail.python.org/mailman3/lists/python-ideas.python.org/ > > Message archived at > > https://mail.python.org/archives/list/python-ideas@python.org/message/6A3DW3... > > Code of Conduct: http://python.org/psf/codeofconduct/ > > -- > Christopher Barker, PhD > Python Language Consulting > > Teaching > Scientific Software Development > Desktop GUI and Web Development > wxPython, numpy, scipy, Cython > Christopher Barker, PhD > > Python Language Consulting > > Teaching > Scientific Software Development > Desktop GUI and Web Development > wxPython, numpy, scipy, Cython