On Fri, Feb 13, 2015 at 5:19 PM, Greg Ewing <greg.ewing@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.

what I think this the "real" use case. ;-) 

2) The LHS is a complex expression that you only want
   to write out and evaluate once.

Can you give an example of this? how can put an expression in the right hand side? I seem to only get errors:

In [23]: l1
Out[23]: [1]

In [24]: l2
Out[24]: [2]

In [25]: (l1 + l2) += [3]
  File "<ipython-input-25-b8781c271c74>", line 1
    (l1 + l2) += [3]
SyntaxError: can't assign to operator

which makes sense -- the LHS is an expression that results in a list, but += is trying to assign to that object. HOw can there be anything other than a single object on the LHS?

In fact, if this worked like I expect and want it to -- that Would work. but that fat hat we've mixed in-place operation with "shorthand for operation plus assignment" makes this a mess.

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 wonder if there is are many real use cases of that -- do people really write:

In [28]: try:
   ....:     t[0] += [4]
   ....: except TypeError:
   ....:     pass

It seems making that change would let things not raise an error that would otherwise.

Or, I suppose, the equivalent of that try:except could be build into augmented assignment..
 
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.

Sure -- but my point is that at least by convention, se keep "mutating an object" and "creating a new object" clearly distinct -- but not in this case.

I'm pretty convinced, band my memory of the conversation when this was added, is that the was a case of some people wanting shorthand like:

i += 1

and others wanted a way to express in-place operations conveniently:

array += 1

And this was seen as a way to kill two birds with one stone -- and that has let to this confusing behavior.

And BOTH are simply syntactic sugar:

i += 1 ==> i = i+1

and 

array += 1 ==> np.add(array, 1, out=array)

I would argue that the seconds is a major win, and the first only a minor win.

( and yes, I did right a bunch of ugly code that looks like the second line before augmented assignment existed.)

But this is all mute -- the cast is well out of the bag on this.

Though if we could clean it up a bit, that would be nice.

-Chris





 

--
Greg

_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/



--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R            (206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115       (206) 526-6317   main reception

Chris.Barker@noaa.gov