[Python-ideas] Adding "+" and "+=" operators to dict
Steven D'Aprano
steve at pearwood.info
Sat Feb 14 03:19:19 CET 2015
On Fri, Feb 13, 2015 at 08:02:56AM -0800, Chris Barker - NOAA Federal wrote:
> > On Feb 12, 2015, at 10:24 PM, Steven D'Aprano <steve at pearwood.info> wrote:
> >> += duplicates the extend method on lists.
> >
> > Yes it does, and that sometimes causes confusion when people wonder why
> > alist += blist is not *quite* the same as alist = alist + blist.
>
> Actually, that's the primary motivator for += and friends -- to
> support in-place operations on mutables. Notably numpy arrays.
I'm not sure that implementing __iadd__ for numpy arrays is much harder
than implementing an iadd method, and there isn't that much difference
in readability between these two possible alternatives:
data += some_numpy_array
data.iadd(some_numpy_array)
If the motivation for augmented assignment was "numpy users don't want
to type a method name", then I think that pandering to them was a poor
decision.
I don't remember the discussion leading up to augmented assignment being
added to the language, but I remember that *before* it was added there
was a steady stream of people asking why they couldn't write:
n += 1
like in C. (And a smaller number wanting to write ++n and n++ too, but
fortunately nowhere near as many.)
[...]
> But the "problem" here is that augmented assignment shouldn't work on
> immutables at all.
That isn't the problem. Having augmented assignment work with immutables
works fine. Even tuples can work perfectly:
py> t = ([1, 2, 3], "spam")
py> t += (None,)
py> t
([1, 2, 3], 'spam', None)
I might have been tempted to say that the *real* problem is mutables,
not immutables, but even that is not the case:
py> t[0][2] += 1000
py> t
([1, 2, 1003], 'spam', None)
Perhaps the actual problem is that objects have no way of signalling to
Python that they have, or have not, performed an in-place mutation, so
that Python knows whether or not to try re-binding to the left hand
reference. Or perhaps the real problem is that Python is so dynamic that
it cannot tell whether a binding operation will succeed. Or that after a
binding fails, that it cannot tell whether or not to catch and suppress
the exception. There's no shortage of candidates for "the real problem".
> But then we wouldn't have the too appealing to resist syntactic sugar
> for integer incrementing.
>
> But are you saying that augmented assignment was simply a mistake
> altogether, and therefore no new use of it should be added at all (
> and you'd deprecate it if you could)?
What's done is done. I certainly wouldn't deprecate it now. If += was a
mistake, then fixing that mistake is more painful than living with it.
Is it a mistake? I don't know. I guess that depends on whether you get
more value from being able to write += then you get from having to deal
with corner cases that fail.
The broader lesson from augmented assignment is that syntax and
semantics are not entirely independent. Syntax that is unproblematic in
C, with C's semantics, has painful corner cases with Python's semantics.
The narrower lesson is that I am cautious about using operators when a
method or function can do. Saving a few keystrokes is not sufficient.
Bringing it back to dicts:
settings.printer_config.update(global_settings, user_settings)
is obvious and easy and will not fail if blob is a named tuple or
printer_config is a read-only property (for example), while:
settings.printer_config += global_settings + user_settings
may succeed and yet still raise an exception.
--
Steve
More information about the Python-ideas
mailing list