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

Что происходит за кулисами, когда python добавляет небольшие ints?

В последнее время я ловил id и понял, что (c?) Python делает что-то весьма разумное: он гарантирует, что маленькие ints всегда имеют одинаковый id.

>>> a, b, c, d, e = 1, 2, 3, 4, 5
>>> f, g, h, i, j = 1, 2, 3, 4, 5
>>> [id(x) == id(y) for x, y in zip([a, b, c, d, e], [f, g, h, i, j])]
[True, True, True, True, True]

Но потом мне пришло в голову задаться вопросом, верно ли то же самое для результатов математических операций. Оказывается, это:

>>> nines = [(x + y, 9) for x, y in enumerate(reversed(range(10)))]
>>> [id(x) == id(y) for x, y in nines]
[True, True, True, True, True, True, True, True, True, True]

Кажется, что он начинает сбой при n = 257...

>>> a, b = 200 + 56, 256
>>> id(a) == id(b)
True
>>> a, b = 200 + 57, 257
>>> id(a) == id(b)
False

Но иногда он работает даже с большими номерами:

>>> [id(2 * x + y) == id(300 + x) for x, y in enumerate(reversed(range(301)))][:10]
[True, True, True, True, True, True, True, True, True, True]

Что здесь происходит? Как это делает python?

4b9b3361

Ответ 1

Python хранит пул объектов int в определенных числах. Когда вы создаете один в этом диапазоне, вы фактически получаете ссылку на ранее существовавший. Я подозреваю, что это по соображениям оптимизации.

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

$ python
Python 3.2 (r32:88445, Apr 15 2011, 11:09:05) 
[GCC 4.5.2 20110127 (prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> x = 300
>>> id(x)
140570345270544
>>> id(100+200)
140570372179568
>>> id(x*2)
140570345270512
>>> id(600)
140570345270576

Источник

PyObject * PyInt_FromLong (long ival) Возвращаемое значение: Новая ссылка. Создать новый целочисленный объект со значением Ival.

Текущая реализация сохраняет массив целых объектов для всех целые числа от -5 до 256, когда вы создайте int в этом диапазоне просто верните ссылку на существующий объект.. Это должно быть можно изменить значение 1. я подозревать поведение Python в этот случай равен undefined.: -)

акцент мой

Ответ 2

Вы попали в необычную ловушку:

id(2 * x + y) == id(300 + x)

Два выражения 2 * x + y и 300 + x не имеют перекрывающихся времен жизни. Это означает, что Python может вычислить левую сторону, взять свой id, а затем освободить целое число до того, как он вычислит правую сторону. Когда CPython освобождает целое число, он помещает его в список свободных целых чисел, а затем повторно использует его для другого целого числа в следующий раз, когда он ему нужен. Таким образом, ваши идентификаторы совпадают, даже когда результат расчетов очень различен:

>>> x, y = 100, 40000
>>> id(2 * x + y) == id(300 + x)
True
>>> 2 * x + y, 300 + x
(40200, 400)

Ответ 3

AFAIK, id не имеет ничего общего с размером параметра. Он ДОЛЖЕН вернуть уникальный идентификатор времени жизни, и он может вернуть тот же результат для двух разных параметров, если они не существуют одновременно.