
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@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