Введение

Все в Python является объектом!

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

Вот несколько важных терминов, которые вы должны иметь в виду, читая оставшуюся часть этой статьи:

Переменная

Переменная — это имя, которое мы присваиваем объекту. В результате в Python переменные часто называются именами.

Объект

Объект — это часть выделенной памяти, которая содержит достаточно места для хранения значения, которое они представляют.

В Python каждый объект имеет два стандартных поля заголовка — поле, представляющее тип объекта, и счетчик ссылок, определяющий, когда объект может быть возвращен.

Ссылка

Ссылка — это указатель из переменной на объект.

Псевдоним

Псевдоним — это альтернативное имя объекта, которое формируется всякий раз, когда к существующему значению объекта присваивается другая переменная.

Назначение

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

>>> a = 5

Правая часть задания всегда оценивается первой. Поэтому сначала создается или извлекается объект. Затем переменная присваивается объекту.

идентификатор() и тип()

Python предоставляет две встроенные функции — id и type — которые помогут нам понять изменяемые и неизменяемые объекты.

Функция id возвращает идентификатор объекта. Возвращаемое значение — это уникальное целое число, представляющее адрес памяти объекта, который остается постоянным в течение всего времени существования объекта. Важно отметить, что значение, возвращаемое этой функцией, будет различаться на разных машинах.

Функция type возвращает тип объекта. Возвращаемое значение является типом объекта.

is и == операторы

Оператор is проверяет, ссылаются ли две переменные на один и тот же объект.

Следовательно, если id(variable_one) = id(variable_two), то variable_one is variable_two вернет True.

>>> a = [1, 2]
>>> b = a
>>> a is b
True
>>> a = 2000
>>> b = 2000
>>> a is b
False

Оператор == проверяет, ссылаются ли две переменные на два объекта, которые содержат одинаковые значения.

>>> a = [1, 2]
>>> b = [2]
>>> a == b
False
>>> a = 2000
>>> b = 2000
>>> a == b
True

Как Python обрабатывает изменяемые объекты

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

Следующие встроенные типы Python3 являются изменяемыми:

  • Списки
  • Словари
  • Наборы (исключая замороженный набор)

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

Давайте посмотрим на это поведение в действии. Что происходит, когда мы создаем список и меняем значение элемента в списке?

>>> a = [1, 2, 3, 4]
>>> a
[1, 2, 3, 4]
>>> id(a)
139903771572616
>>> a[0] = 5
>>> a
[5, 2, 3, 4]
>>> id(a)
139903771572616

Мы заметили, что идентификатор объекта списка, возвращаемый функцией id(), не меняется.

Если бы мы сделали следующее, то получили бы другой результат:

>>> a = [1, 2, 3, 4]
>>> id(a)
140516804388872
>>> a = a + [5]
>>> id(a)
140516804397128

В этом примере мы создаем совершенно новый объект. Поэтому адрес a изменится.

Осторожно!

>>> a = [1, 2, 3, 4]
>>> id(a)
140516804388872
>>> a += [5]
>>> id(a)
140516804388872

В этом примере оператор += эквивалентен методу extend() типа списка, когда левая часть уравнения является списком, а правая часть уравнения является итерируемым. Поскольку функция extend() изменяет список, выполняя изменение на месте, а не создавая новый объект, адрес a не изменится.

Как Python обрабатывает неизменяемые объекты

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

Следующие встроенные типы Python3 являются неизменяемыми:

  • Числа
  • Струны
  • Кортежи
  • Замороженный

Неизменяемые объекты не поддерживают изменения на месте. Следовательно, каждый раз, когда мы намерены изменить значение, присвоенное переменной, необходимо создавать новый объект или ссылаться на него.

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

Числа

Python кэширует целые числа в диапазоне [-5, 256]. Все переменные, назначенные объекту с целочисленным значением в этом диапазоне, будут ссылаться на одни и те же адреса памяти. Другими словами, новые объекты не создаются, поскольку все ссылки будут ссылаться на кэшированные объекты.

>>> a = 10
10105376
>>> b = 10
10105376
>>> a = 10 + 42
>>> a 
10106720
>>> b = 52
10106720

Каждый раз, когда переменная присваивается объекту с целочисленным значением вне диапазона [-5, 256], создается новый объект.

>>> a = 257
>>> id(a)
140441553954704
>>> b = 257
>>> id(b)
140441554550672

Струны

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

Когда другая переменная назначается объекту с тем же строковым значением, Python оптимизирует ресурсы, заставляя две переменные ссылаться на один и тот же объект. Поэтому никаких новых объектов в этом случае не создается!

Обратите внимание, это поведение отличается от того, которое мы наблюдали для целых чисел за пределами диапазона [-5, 256].

>>> a = 'hello'
>>> b = 'hello'
>>> id(a)
140441553317480
>>> id(b)
140441553317480

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

>>> a = 'hi'
>>> b = 'hello'
>>> id(a)
140441553317536
>>> id(b)
140441553317480

Кортежи

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

>>> a = (1, 2)
>>> b = (1, 2)
>>> id(a)
140049862104392
>>> id(b)
140049829553736

Несмотря на то, что переменные a и b содержат одно и то же значение, они ссылаются на совершенно разные объекты.

Осторожно!

Хотя кортеж неизменяем, вы все равно можете изменить содержимое изменяемого объекта внутри кортежа!

>>> a = (1, [2, 5])
>>> a[1][0] = 10
>>> a
(1, [10, 5])

Как неизменяемые и изменяемые объекты передаются функциям

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

Неизменяемые объекты

Когда неизменяемый объект передается функции, передаваемый аргумент ведет себя как вызов по значению. В этом случае функция создает и использует локальную копию переданного аргумента. Поэтому в исходный объект нельзя внести никакие изменения.

>>> def test_immutable(a):
...      a += 1
...
>>> a = 5
>>> test_immutable(a)
>>> a
5

Изменяемые объекты

Когда изменяемый объект передается функции, передаваемый аргумент ведет себя как вызов по ссылке. В этом случае функция получает ссылку на исходный объект. Поскольку ссылка представляет собой автоматически отслеживаемый указатель от имени переменной к объекту, мы можем изменить исходный объект в рамках функции.

>>> def test_immutable(a):
...      a.append(5)
...
>>> a = [1, 2]
>>> test_immutable(a)
>>> a
[1, 2, 5]

Источники

https://www.python-course.eu/passing_arguments.php
http://www.openbookproject.net/thinkcs/python/english2e/ch09.html#objects-and-values