Found the answer on IRC.
t[0] += [1] is several discrete actions:
- loading
t[0]
- building a new list with
1 in it
- adding that
[1] to whatever t[0] is
- reassigning
t[0]
It seems that x += y is basically x = x + y (but, is it?)
The tricky bit is that += implies assignment to both the tuple t and to the list t[0]
t[0] += [1] is not literally t[0] = t[0] + [1], it is: t[0] = t[0].__iadd__([1])
What really happens is:
__iadd__ both mutates the list and returns it. So the list (which is the first element in t) has already got 1 appended to it.
- tuple's mutation is attempted in-place as well, but tuples are immutable, resulting in the exception.
Why is this not visible in plain sight? Because a n00b like me would expect t[0] += [1] to either succeed all together or fail, because it's one short line of python. But that's not always the case.