From: "Guido van Rossum" email@example.com
Um, in the code. :-( Using dis(), you'll find that x+=3 executes the following:
6 LOAD_FAST 0 (x) 9 LOAD_CONST 1 (1) 12 DUP_TOPX 2 15 BINARY_SUBSCR 16 LOAD_CONST 2 (3) 19 INPLACE_ADD 20 ROT_THREE 21 STORE_SUBSCR
How does Python decide that sequence elements are immutable?
Huh? It doesn't. If they were mutable, had you expected something else?
Actually, yes. I had expcected that Python would know it didn't need to "put the thing back in", since the thing gets modified in place. Knowing that it doesn't work that way clears up a lot.
>>> x = [, , ] >>> x +=  >>> x [, [3, 6], ] >>>
Well of /course/ I know that's the result. The question was, how is the result achieved?
Basically, += on an attribute or subscripted container does the following:
(1) get the thing out (2) apply the inplace operation to the thing (3) put the thing back in
The inplace operation, of course, is a binary operator that *may* modify its first operand in place, but *must* return the resulting value; if it modified the first operand in place, it *should* return that operand. If a type doesn't support an inplace operation, the regular binary operator is invoked instead.
That's the easy part.
Does this help? (The whole thing is designed to be intuitive, but that probably doesn't work in your case. :-)
I use this stuff from Python without thinking about it, but when it comes to building new types, I sometimes need to have a better sense of the underlying mechanism.
P.S. Say, you could optimize away putting the thing back at runtime if the inplace operation returns its first argument... but you probably already thought of that one.