Поведение a += и a = a + для списков в Python
@python_quizРазберем этот квиз
Коротко: одинаково выглядящие записи могут вести себя по‑разному из‑за мутабельности объектов и того, как реализованы операции в Python. Разберём шаги, покажем код и объясним, почему конечный вывод такой, а не другой.
Условие (код)

Пошаговый разбор
- a = [1] — создаётся список [1].
b = a— b и a ссылаются на один и тот же объект (алиас).- a += [2]
- Для списков оператор += вызывает метод __iadd__, который мутирует список на месте (расширяет существующий объект).
- Поскольку a и b указывают на один объект, изменения видны и через b.
- После этой строки список будет [1, 2] и id(a) == id(b).
a = a+ [3]
- Оператор + для списков создаёт новый список (результат __add__), не мутируя исходный.
- Присваивание a = ... перенаправляет переменную a на новый объект, b остаётся указывать на старый.
- В результате a становится [1, 2, 3], а b остаётся [1, 2].
Итоговый вывод: [1, 2, 3] [1, 2]
Демонстрация с id(), чтобы увидеть смену объектов

Ожидаемый вывод (ids будут отличаться на вашей машине, пример):

Почему это важно
- Операция += может быть in-place (мутация) для мутабельных типов (списки, bytearray и т.д.), что изменяет все ссылки на объект.
- Операция + обычно создаёт новый объект (для списков возвращается новый список).
- Поведение += зависит от того, реализован ли у объекта
__iadd__. Если__iadd__отсутствует или возвращает NotImplemented, Python прибегает к__add__и создаёт новый объект.
Примеры отличий:
- Для immutable типов (кортежи, строки) += создаёт новый объект, т.к. в них нет мутации.
- Для пользовательских классов поведение определяется реализацией
__iadd__и__add__.
Анализ вариантов (кратко)
Представленные варианты вывода:
- "[1, 2, 3] [1, 2]" — совпадает с реальным результатом: после in-place расширения и последующего создания нового списка для a.
- Остальные варианты не соответствуют сочетанию in-place изменения и последующего создания нового объекта:
- Оба списка [1,2,3] означали бы, что второе присваивание тоже мутировало исходный объект — это не так.
- Оба [1,2] означали бы, что a не получил [3] после второго шага — неверно.
- Перестановка [1,2] [1,2,3] не имеет смысла, так как b не мог увеличиться до 3, если a был перенаправлен.
Выводы и рекомендации
- Будьте внимательны с aliasing (несколькими переменными, ссылающимися на один объект). Мутации через одну переменную видны через другие.
- Используйте .copy() или list() если нужно отдельное независимое копирование:
b = a.copy() илиb = list(a). - При чтении кода помните: += для списков мутирует объект, а выражение
a = a+ ... создаёт новый объект. Это источник многих тонких ошибок.
Если хотите, могу показать дополнительные примеры с кортежами, строками или пользовательскими классами, чтобы сравнить поведение.