[Python-ideas] Adding "+" and "+=" operators to dict

Andrew Barnert abarnert at yahoo.com
Sat Feb 14 03:12:42 CET 2015


On Feb 13, 2015, at 17:19, Greg Ewing <greg.ewing at canterbury.ac.nz> wrote:

> Chris Barker - NOAA Federal wrote:
>> But why does it work
>> that way? Because it needs to work on immutable objects. If it didn't,
>> then you wouldn't need the "assign back to the original name" step.
> 
> This doesn't make it wrong for in-place operators to
> work on immutable objects. There are two distinct use
> cases:
> 
> 1) You want to update a mutable object in-place.
> 
> 2) The LHS is a complex expression that you only want
>   to write out and evaluate once.
> 
> Case (2) applies equally well to mutable and immutable
> objects.
> 
> There are ways that the tuple problem could be fixed, such
> as skipping the assignment if __iadd__ returns the same
> object. But that would be a backwards-incompatible change,
> since there could be code that relies on the assignment
> always happening.

I think it's reasonable for a target to be able to assume that it will get a setattr or setitem when one of its subobjects is assigned to. You might need to throw out cached computed properties, or move the element in sorted order, or call a trace-on-change callback, etc. This change would mean that augmented assignment isn't really assignment at all. (And if you don't _want_ assignment, you can always call t[0].extend([1]) instead of t[0] += [1].)

>> If it's in-place for a mutable object, it needs to return self. But
>> the python standard practice is that methods that mutate objects
>> shouldn't return self ( like list.sort() ) for instance.
> 
> The reason for that is to catch the mistake of using a
> mutating method when you meant to use a non-mutating one.
> That doesn't apply to __iadd__, because you don't
> usually call it yourself.

I think there's another big distinction: a method call is an expression, not a statement, so if it returned self, you could chain multiple mutations into a single statement. Because it returns None, you get only one mutation per statement. And it's the leftmost thing in the statement that's being mutated, except in uncommon or pathological code.

Unlike many other languages, assignment (including augmented assignment) is a statement in Python, so that isn't an issue. So you still only get one mutation per statement, and to the leftmost thing, when using augmented assignment. (And, as you say, you usually don't call __iadd__ itself; if you really wanted to call it explicitly and chain calls together, you could, but that falls under pathological code.)


More information about the Python-ideas mailing list