Общий ответ заключается в том, что он +=
пытается вызвать __iadd__
специальный метод, а если он недоступен, он пытается использовать __add__
вместо него. Итак, проблема в различии этих специальных методов.
Этот __iadd__
специальный метод предназначен для добавления на месте, то есть он изменяет объект, на который действует. __add__
Специальный метод возвращает новый объект , а также используется для стандартного +
оператора.
Поэтому, когда +=
оператор используется для объекта, который имеет __iadd__
определенный объект, изменяется на месте. В противном случае вместо этого он попытается использовать простой __add__
и вернуть новый объект.
Вот почему для изменяемых типов, таких как списки, +=
изменяется значение объекта, тогда как для неизменяемых типов, таких как кортежи, строки и целые числа, вместо этого возвращается новый объект ( a += b
становится эквивалентным a = a + b
).
Для типов, которые поддерживают и то, __iadd__
и другое __add__
, поэтому вы должны быть осторожны при выборе из них. a += b
вызовет __iadd__
и изменит a
, тогда как a = a + b
создаст новый объект и назначит его a
. Это не одна и та же операция!
>>> a1 = a2 = [1, 2]
>>> b1 = b2 = [1, 2]
>>> a1 += [3] # Uses __iadd__, modifies a1 in-place
>>> b1 = b1 + [3] # Uses __add__, creates new list, assigns it to b1
>>> a2
[1, 2, 3] # a1 and a2 are still the same list
>>> b2
[1, 2] # whereas only b1 was changed
Для неизменяемых типов (где у вас их нет __iadd__
) a += b
и a = a + b
эквивалентны. Это то, что позволяет вам использовать +=
для неизменяемых типов, что может показаться странным дизайнерским решением, пока вы не решите, что в противном случае вы не могли бы использовать +=
для неизменных типов, таких как числа!