Это полностью зависит от объекта i.
+=вызывает __iadd__метод (если он существует - возвращается к нему, __add__если он не существует), тогда как в некоторых случаях+ вызывает __add__метод 1 или __radd__метод 2 .
С точки зрения API, __iadd__предполагается использовать для изменения изменяемых объектов на месте (возвращая объект, который был мутирован), тогда как __add__должен возвращать новый экземпляр чего-либо. Для неизменяемых объектов оба метода возвращают новый экземпляр, но __iadd__помещают новый экземпляр в текущее пространство имен с тем же именем, что и у старого экземпляра. Вот почему
i = 1
i += 1
похоже на прирост i. В действительности вы получаете новое целое число и назначаете его «поверх», iтеряя одну ссылку на старое целое число. В этом случае i += 1точно так же, как i = i + 1. Но с большинством изменяемых объектов это другая история:
В качестве конкретного примера:
a = [1, 2, 3]
b = a
b += [1, 2, 3]
print a #[1, 2, 3, 1, 2, 3]
print b #[1, 2, 3, 1, 2, 3]
по сравнению с:
a = [1, 2, 3]
b = a
b = b + [1, 2, 3]
print a #[1, 2, 3]
print b #[1, 2, 3, 1, 2, 3]
обратите внимание на то, как в первом примере, bи aкогда я ссылаюсь +=на один и тот же объект, когда я использую bего, он действительно изменяется b(и aвидит это изменение тоже - в конце концов, он ссылается на тот же список). Во втором случае, однако, когда я это делаю b = b + [1, 2, 3], он берет список, который bссылается, и объединяет его с новым списком [1, 2, 3]. Затем он сохраняет объединенный список в текущем пространстве имен как b- безотносительно к тому, какая bстрока была раньше.
1 В выражении x + y, если x.__add__не выполняются или если x.__add__(y)возврат NotImplemented и xи yимеют разные типы , то x + yпытается вызов y.__radd__(x). Итак, в случае, если у вас есть
foo_instance += bar_instance
если Fooне реализует __add__или __iadd__то результат здесь такой же, как
foo_instance = bar_instance.__radd__(bar_instance, foo_instance)
2 В выражении foo_instance + bar_instance, bar_instance.__radd__будет судим , foo_instance.__add__ если тип bar_instanceявляется подклассом типа foo_instance(например issubclass(Bar, Foo)). Рационально это потому , что Barв каком - то смысле «более высокого уровня» объекта , чем Fooтак Barдолжны получить возможность переопределения Fooповедения «s.
+=действует какextend()в случае списков.