Why do Python emit STORE_SUBSTR when there's already an INPLACE_ADD?

115 views Asked by At

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?

2

There are 2 answers

0
user2357112 On BEST ANSWER

This is because INPLACE_ADD only requests that the operation be done in place if possible; if the object is immutable or has not bothered to implement __iadd__, INPLACE_ADD falls back on regular, not-in-place addition. If the code was

t = [1, 2, (30)]
t[2] += (40,)

it 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.

0
Ashwini Chaudhary On

That's because t[2] += [40] works like this:

temp = t[2]
temp += [40] # INPLACE_ADD
t[2] = temp  # STORE_SUBSCR

Python actually doesn't update the list in-place, the value is stored in a temporary variable first.

Proof:

>>> lst  = [[1], [2], [3]]
>>> def func():
...     lst[0] = [100]
...     return [40]
...
>>> lst[0] += func()
>>> lst
[[1, 40], [2], [3]]  # Not [[100, 40], [2], [3]]