0
>>> r = [[]]
>>> r[0] = r[0] + 'abc'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "str") to list
>>> r[0] += 'abc'
>>> r
[['a', 'b', 'c']]

Could somebody explain why second assignment works but not the first one ?

Eugen
  • 2,292
  • 3
  • 29
  • 43
  • This question could be written without the outer list. `r = [];r + 'abc'` and `r=[];r+='abc'`. Then answers don't have to include a mention of the inner list. – tdelaney Mar 01 '20 at 20:32
  • 1
    @quamrana - that's a different problem where a class level list is shared by all of its instance objects. – tdelaney Mar 01 '20 at 21:12

1 Answers1

1

Why += works and + doesn't work is "that's how its coded". But I haven't figured out any good reason for it. Lets focus simply on list addition

operator         magic method   list equiv
--------         ------------   ----------
+= (inplace add) __iadd__       list_inplace_concat
+  (add)         __add__        list_concat

Inplace Add / list_inplace_concat works on any sequence. Under the covers, python simply calls list.extend which turns the right hand side into an iterator and so works with all sequences

>>> test = []
>>> test += 'abc'
>>> test
['a', 'b', 'c']

Add / list_concat is hardcoded to work only with other lists. The underlying C code uses the internal data structure of the list to copy its elements.

>>> test + 'abc'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "str") to list

Change the right hand side to a list and it works

>>> test + list('abc')
['a', 'b', 'c', 'a', 'b', 'c']
>>> 

list_concat is optimized to use the size of the two lists to know exactly how large the new list needs to be. Then it does member copy at the C structure level. What puzzles me is why there isn't a fallback when the "not a list" condition is detected. The list could be copied and extended.

tdelaney
  • 73,364
  • 6
  • 83
  • 116