

Understanding Python's augmented assignment (a += b) - ceronman
http://stupidpythonideas.blogspot.com/2015/02/augmented-assignments-b.html

======
icebraining
Nice article, though I already understood the matter. Thanks for the link to
PEP 463[1], though; I can see it cleaning up some of our code. Do you know if
there have been any developments into implementing it?

[1]
[http://legacy.python.org/dev/peps/pep-0463/](http://legacy.python.org/dev/peps/pep-0463/)

~~~
maxerickson
It died:

[https://mail.python.org/pipermail/python-
dev/2014-March/1331...](https://mail.python.org/pipermail/python-
dev/2014-March/133118.html)

(the PEP author posts a couple messages in the thread too)

------
danbruc
What this article says about C++ is not true.

~~~
anon4
It seems to me it describes pretty much what happens in C++, but with
pythonized syntax, because explaining the exact syntax of all the sigils would
be too much for such a short article.

~~~
danbruc
Absolutely not. Take for example the part about t = [0, 1] followed by t[0] =
2. t[0] does return nothing at all, neither 0 nor any strange complex object.
It just evaluates to the memory address of the first element of the array. The
idea expressed later that C++ unlike Python treats every piece of code exactly
the same no matter whether it appears on the left hand side or the right hand
side of an assignment operator is fundamentally wrong.

~~~
Leszek
Well no, for

    
    
        std::vector<int> t = {0, 1};
    

t[0] calls operator[], which returns an int&. This is precisely an lvalue
reference, which is kind of like a memory address, but int& is a type in its
own right. Calling it a "reference object" is not entirely correct, but it's
also not entirely incorrect. And let's not get started on vector<bool>...

------
aftbit
Why couldn't Python do something like:

    
    
        >>> _tmp = getitem(t, 0)
        >>> setitem(t, 0, _tmp)
        >>> try:
        >>>     _tmp2 = _tmp.__iadd__([2])
        >>> except AttributeError:
        >>>     _tmp2 = _tmp.__add__([2])
        >>> setitem(t, 0, _tmp2)
    

Then if the first setitem raises, the rest of the code will be skipped.
Obviously this isn't perfect:

1\. If setitem has strange side-effects, this will cause them to happen twice.
2\. If setitem raises based on the value (rather than the key), this won't
notice that.

But otherwise, it seems like a pretty straightforward improvement, no?

------
danbruc
The example look ill-conceived to begin with. If you want to extend the list
that is the first element of the tuple just use t[0].extend([1]). Using an
augmented assignment operator makes no sense if the left hand side can not be
assigned to. I don't know Python well enough to tell why it does not check if
the left hand side can be assigned to before evaluating the right hand side,
i.e. why it dos not check that __setitem__ is present. This would make the
behavior more similar to a compiled statically typed language where this would
be a compile time error and the right hand side would never get evaluated.

~~~
aftbit
In fact, the second half of the article is about why it doesn't do that. Also,
Python is not a compiled statically typed language, and doesn't have compile
errors.

------
peterderivaz
I ran into this when computing PSNR comparisons using a Numpy function that
returned a numpy integer type:

    
    
        >>> import numpy
        >>> x=0
        >>> y=numpy.int32(2*10**9)
        >>> x+=y
        >>> x+=y
        >>> x
        -294967296
    

In later versions of Python this gives a RuntimeWarning so this is less likely
to cause problems now.

~~~
PhantomGremlin
Python 2.7.2 on OS X 10.8.5 behaves even more strangely. I get:

    
    
       >>> import numpy
       >>> x=0
       >>> y=numpy.int32(2*10**9)
       >>> y
       2000000000
       >>> x+=y
       >>> x
       2000000000
       >>> x+=y
       >>> x
       4000000000
       >>> x*x
       -2446744073709551616
       >>> y*y
       __main__:1: RuntimeWarning: overflow encountered in int_scalars
       -1651507200
    

I didn't think it was possible to get integer wraparound in Python. I guess
it's because the "int32" from numpy "breaks" x, which subsequently no longer
behaves like a python variable.

------
cagriaksay
Official FAQ is easier to understand. I recommend reading that first before
the article.

------
zrail
This is a wonderful explanation of a deeply confusing situation. Thank you for
posting.

