If you disassemble the following function
def test():
t = (1, 2, [30])
t[2] += [40]
return t
You'll see that the corresponding bytecode for t[2] += [40] looks like this:
3 18 LOAD_FAST 0 (t)
21 LOAD_CONST 2 (2)
24 DUP_TOPX 2
27 BINARY_SUBSCR
28 LOAD_CONST 4 (40)
31 BUILD_LIST 1
34 INPLACE_ADD
35 ROT_THREE
36 STORE_SUBSCR
[40] is concatenated to the list stored in t[2] after INPLACE_ADD, why does Python decide to add a STORE_SUBSCR anyway?
This is because
INPLACE_ADDonly requests that the operation be done in place if possible; if the object is immutable or has not bothered to implement__iadd__,INPLACE_ADDfalls back on regular, not-in-place addition. If the code wasit would obviously be necessary to store the new tuple back into
t[2], since the operation produces a new tuple instead of mutating the old one.