Поведение оператора += с кортежами в Python

Поведение оператора += с кортежами в Python

@python_quiz

Разберем этот квиз

Коротко: код

python

напечатает

Ниже объясню, почему так происходит, покажу демонстрацию с id() и сравню с поведением для изменяемых типов (например, списков).

Разбор кода по шагам

  1. a = b = (1,)

Оба имени, a и b, ссылаются на один и тот же кортеж (1,).

  1. a += (2,)

Оператор += для кортежей не изменяет существующий кортеж (кортежи неизменяемы). В случае неизменяемого объекта Python фактически выполняет операцию сложения и переназначает имя a на новый объект, равный (1, 2). Имя b продолжает ссылаться на старый кортеж (1,).

  1. print(a, b)

Выводит два кортежа: новый, связанный с a, и исходный, связанный с b.

Почему так — технически

  • Кортежи неизменяемы, у них нет поведения "изменяющегося" результата для +=. При выполнении a += (2,) Python вызывает реализацию in-place (если она есть, __iadd__), а если её нет или объект неизменяем, использует результат обычного сложения (a = a + (2,)). В итоге создаётся новый объект и имя a переназначается на него.
  • Выражение a = b = (1,) создает один объект и связывает с ним оба имени. Переназначение a не затрагивает b.

Демонстрация с id()

Ниже код показывает, что id(a) изменился, а id(b) остался прежним:

python

Ожидаемый вывод (id будут числа, разные для нового и старого объектов):

Как видно, id(a) поменялся — создан новый кортеж; id(b) остался тем же — b всё ещё ссылается на исходный кортеж.

Контраст: списки (изменяемый тип)

Для сравнения, со списками поведение другое:

python

Вывод:

Здесь id не меняется — операция += у списков выполняет добавление элементов "на месте" (метод __iadd__ реализован), поэтому оба имени видят изменённый объект.

Вывод

  • Оператор += может либо изменить объект "на месте" (если тип изменяем и реализует __iadd__), либо создать новый объект и переназначить имя (часто для неизменяемых типов).
  • Для кортежей a += b фактически создаёт новый кортеж и привязывает его к имени a, в то время как b остаётся ссылаться на исходный кортеж. В результате печать покажет (1, 2) и (1,) соответственно.

Report Page