Почему число нельзя изменить так же, как список?
В предыдущей статье мы увидели довольно странное на первый взгляд поведение:
a = [1, 2]
b = a
a.append(3)
print(b) # [1, 2, 3]
Создаётся ощущение, будто Python “связывает” переменные между собой. На самом деле никакой связи между переменными нет - есть только один объект, к которому привязано несколько имён.
Но теперь возникает очень естественный вопрос.
Если список можно изменить “на месте”, почему тогда с числами всё ведёт себя иначе?
Рассмотрим похожий пример:
x = 10
y = x
x = 20
print(y)
И здесь результат уже совершенно другой:
10
Переменная y осталась равной 10, хотя мы явно изменили x.
Почему так происходит?
Чтобы ответить на этот вопрос, важно заметить одну тонкую, но ключевую деталь: в Python есть разные типы объектов, и они по-разному ведут себя при “изменении”.
Начнём с чисел.
Когда мы пишем:
x = 10
создаётся объект числа 10, и имя x начинает на него ссылаться:
x ───► 10
Теперь выполняется строка:
x = 20
Здесь важно не путать происходящее с изменением объекта.
Число 10 не превращается в 20. Объект 10 вообще не меняется - он остаётся тем же самым объектом.
Вместо этого имя x просто перестаёт ссылаться на старый объект и начинает ссылаться на новый:
x ───► 20
y ───► 10
Объект 10 при этом продолжает существовать, потому что на него всё ещё ссылается переменная y.
Теперь посмотрим на список.
a = [1, 2]
Создаётся один объект списка:
a ───► [1, 2]
А теперь ключевой момент:
a.append(3)
Эта операция не создаёт новый список.
Она изменяет уже существующий объект “на месте”.
После этого:
a ───► [1, 2, 3]
Если раньше у нас было два имени:
a = [1, 2]
b = a
то схема выглядела так:
a ─┐
├──► [1, 2]
b ─┘
И когда мы вызываем:
a.append(3)
мы изменяем сам объект, а не имя. Поэтому оба имени продолжают указывать на один и тот же, уже изменённый список:
a ─┐
├──► [1, 2, 3]
b ─┘
Теперь мы подходим к главному различию.
Число 10 нельзя изменить.
Список можно.
Это не случайность и не особенность синтаксиса - это фундаментальное свойство объектов в Python.
Одни объекты после создания не могут измениться вообще. Любая “попытка изменения” приводит к созданию нового объекта и переназначению имени.
Другие объекты позволяют менять своё внутреннее состояние без создания нового объекта.
Именно поэтому:
- число ведёт себя как “неизменяемый объект”
- список ведёт себя как “изменяемый объект”
Попробуем собрать это в одну интуитивную картину.
Если объект неизменяемый, то он как будто “застывает” в своём состоянии. Если нужно новое значение - появляется новый объект.
Если объект изменяемый, то он остаётся тем же самым объектом, но его содержимое можно менять внутри.
И теперь становится понятно, почему поведение с числами и списками различается:
- в случае чисел мы всегда работаем с новым объектом при изменении значения
- в случае списков мы меняем уже существующий объект
И тут возникает важное следствие, которое мы будем постоянно видеть дальше:
Поведение программы в Python определяется не тем, что “лежит в переменной”, а тем, изменяем ли мы объект или просто переназначаем имя.
И теперь у нас наконец появляется возможность назвать вещи своими именами.
То, что мы наблюдали в предыдущих статьях, называется:
- изменяемые объекты (mutable)
- неизменяемые объекты (immutable)
Но теперь это уже не абстрактные термины.
Это просто названия того поведения, которое мы уже увидели на практике.
В следующей статье мы как раз аккуратно введём эти понятия и соберём всю картину целиком: какие объекты бывают в Python и почему это деление настолько важно для всего языка.