В предыдущей статье мы столкнулись с довольно любопытным наблюдением.

Списки можно изменять:

numbers = [1, 2]

numbers.append(3)

print(numbers)

Результат:

[1, 2, 3]

А вот с числами похожий трюк не работает.

Когда мы пишем:

x = 10
x = 20

объект со значением 10 не превращается в объект со значением 20. Вместо этого имя x начинает ссылаться на другой объект.

На первый взгляд это выглядит как два совершенно разных поведения.

На самом деле Python делит все объекты на две большие группы.

Первая группа называется изменяемыми объектами (mutable objects).

Вторая - неизменяемыми объектами (immutable objects).


Начнём с изменяемых объектов.

Изменяемым называется объект, внутреннее состояние которого можно изменить после создания.

Список - классический пример такого объекта.

Создадим список:

numbers = [1, 2]

После этого можно добавлять элементы:

numbers.append(3)

удалять их:

numbers.remove(2)

или заменять существующие значения:

numbers[0] = 100

Во всех этих случаях Python работает с одним и тем же объектом.

Объект не исчезает и не создаётся заново.

Меняется только его содержимое.

Именно поэтому несколько имён, ссылающихся на один список, будут видеть одинаковые изменения.


Теперь посмотрим на неизменяемые объекты.

Их состояние нельзя изменить после создания.

Возьмём число:

x = 10

Попробуем получить из него число 20:

x = 20

Может показаться, что объект изменился.

Но на самом деле произошло другое.

Старый объект со значением 10 остался прежним.

Просто имя x перестало на него ссылаться и начало ссылаться на новый объект.

То же самое происходит со строками.

Например:

name = "Python"

Попробуем добавить текст:

name = name + " 3"

Кажется, будто строка изменилась.

Но фактически Python создал новую строку:

"Python 3"

и переназначил имя name.

Исходная строка "Python" при этом осталась неизменной.


Здесь полезно сделать небольшую паузу и обратить внимание на важную мысль.

Когда говорят, что объект изменяемый или неизменяемый, речь идёт именно об объекте.

Не о переменной.

Не об имени.

Не о типе присваивания.

А именно об объекте, который находится в памяти.

Это различие кажется мелочью, но позже оно поможет избежать множества ошибок.


Какие объекты чаще всего оказываются неизменяемыми?

Наиболее распространённые примеры:

10
3.14
True
"hello"
(1, 2, 3)

То есть:

  • числа;
  • логические значения;
  • строки;
  • кортежи.

Все они после создания не могут изменить своё содержимое.

К изменяемым объектам относятся:

[1, 2, 3]
{"name": "Anton"}
{"python", "java"}

То есть:

  • списки;
  • словари;
  • множества.

Их содержимое можно менять после создания.


На этом этапе может возникнуть вполне разумный вопрос.

Если изменяемые объекты кажутся более гибкими, почему бы не сделать изменяемыми вообще всё?

Ответ довольно прост.

Неизменяемые объекты намного проще использовать и безопаснее хранить.

Если объект гарантированно не может измениться, то Python может смелее его переиспользовать, быстрее сравнивать и эффективнее хранить в памяти.

Кроме того, программисту не нужно переживать, что кто-то случайно изменит значение объекта в другой части программы.

Поэтому в языке существуют обе категории, и каждая решает свои задачи.


Теперь мы уже можем сформулировать более полную модель работы Python.

Когда мы пишем:

x = something

происходит не запись данных в переменную.

Имя начинает ссылаться на объект.

После этого всё зависит от самого объекта.

Если объект изменяемый, его состояние можно менять на месте.

Если объект неизменяемый, любые изменения приводят к созданию нового объекта.


И вот теперь у нас наконец достаточно знаний, чтобы задать следующий интересный вопрос.

Если два списка содержат одинаковые данные, считаются ли они одинаковыми?

Например:

a = [1, 2, 3]
b = [1, 2, 3]

Это один объект или два?

И почему Python иногда использует ==, а иногда is?

Об этом и поговорим в следующей статье. 🚀