Подтвердить что ты не робот

Прохождение Python по ссылкам

Здравствуйте, я пытаюсь понять, как работает Python по ссылке. У меня есть пример:

>>>a = 1
>>>b = 1
>>>id(a);id(b)
140522779858088
140522779858088

Это имеет смысл, поскольку a и b ссылаются на то же значение, что и у них. Я не совсем понимаю, как этот пример:

>>>a = 4.4
>>>b = 1.0+3.4
>>>id(a);id(b)
140522778796184
140522778796136

Отличается от этого примера:

>>>a = 2
>>>b = 2 + 0
>>>id(a);id(b)
140522779858064
140522779858064

Это потому, что в третьем примере объект 0 int рассматривается как "Нет" интерпретатором и не распознается как нуждающийся в другом идентификаторе от объекта, для которого переменная "a" ссылается (2)? В то время как во втором примере "b" добавляет два разных объекта int, и интерпретатор выделяет память для обоих этих объектов, которые будут добавлены, что дает переменную "a", другую идентификацию из переменной "b"?

4b9b3361

Ответ 1

В вашем первом примере имена a и b являются "ссылками" на один и тот же объект из-за интернирования. Оператор присваивания привел к целому числу с тем же id только потому, что он повторно использовал ранее существовавший объект, который уже висел в памяти. Это не надежное поведение целых чисел:

>>> a = 257
>>> b = 257
>>> id(a), id(b)
(30610608, 30610728)

Как показано выше, если вы выберете достаточно большое целое число, то оно будет вести себя так, как будут вестись поплавки во втором примере. И интернирование небольших целых чисел в любом случае необязательно на языке Python, это, случается, как деталь реализации CPython: это оптимизация производительности, направленная на то, чтобы избежать накладных расходов на создание нового объекта. Мы можем ускорить процесс кэширования обычно используемых целых экземпляров за счет более высокого объема памяти интерпретатора Python.

Не думайте о "ссылке" и "значении" при работе с Python, модель, которая работает для C, здесь не работает. Вместо этого подумайте о "именах" и "объектах".

names

На приведенной выше диаграмме показан ваш третий пример. 2 - это объект, a и b - это имена. У нас могут быть разные имена, указывающие на один и тот же объект. И объекты могут существовать без какого-либо имени.

Присвоение переменной только прикрепляет nametag. И удаление только переменной удаляет nametag. Если вы помните эту идею, то объектная модель Python никогда вас не удивит.

Ответ 2

Как указано здесь, CPython кэширует целые числа от -5 до 256. Таким образом, все переменные в этом диапазоне с одинаковым значением имеют один и тот же идентификатор (я бы не поставил для этого для будущих версий, хотя, но это текущая реализация)

Нет такой вещи для поплавков, вероятно, потому, что существует "бесконечность" возможных значений (ну не бесконечная, но большая из-за плавающей запятой), поэтому вероятность вычисления одного и того же значения различными способами действительно низка по сравнению с целыми числами.

>>> a=4.0
>>> b=4.0
>>> a is b
False

Ответ 3

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

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

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

Проблема заключается в том, что CPython "кэширует" некоторые общие целочисленные значения, поэтому для сохранения памяти не существует нескольких объектов с одинаковым значением, а 2 является одним из этих целых чисел с кешем, поэтому каждый раз, когда переменная указывает на целое число 2 будет иметь одинаковый идентификатор (его значение будет отличаться для разных исполнений python).