Почему (0-6) -6 = False? [дубликат]


Возможный дубликат:
оператор Python " is " ведет себя неожиданно с целыми числами

Сегодня я попытался отладить свой проект и после нескольких часов анализа получил следующее:

>>> (0-6) is -6
False

Но,

>>> (0-5) is -5
True

Не могли бы вы объяснить мне, почему? Может быть, это какая-то ошибка или очень странное поведение.

> Python 2.7.3 (default, Apr 24 2012, 00:00:54) [GCC 4.7.0 20120414 (prerelease)] on linux2
>>> type(0-6) 
<type 'int'>
>>> type(-6) 
<type 'int'>
>>> type((0-6) is -6)
<type 'bool'>
>>> 
4 126

4 ответа:

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

Этот артефакт подробно описан в http://www.laurentluce.com/posts/python-integer-objects-implementation/, и мы могли бы проверить текущий исходный код в http://hg.python.org/cpython/file/tip/Objects/longobject.c .

Определенная структура используется для ссылки на малые целые числа и совместного использования их, чтобы доступ был быстрым. Это массив из 262 указателей на целочисленные объекты. Эти целочисленные объекты выделяются во время инициализации в блоке целочисленных объектов, который мы видели выше. Диапазон малых чисел-от -5 до 257. Многие программы Python тратят много времени на использование целых чисел в этом диапазоне, так что это разумное решение.

это только деталь реализации CPython, и вы не должны полагаться на это. например, PyPy реализовал id целого числа, чтобы вернуть себя, так что (0-6) is -6 всегда верно, даже если они являются" разными объектами " внутри; это также позволяет настроить, следует ли включать это целочисленное кэширование, и даже установить нижнюю и верхнюю границы. Но в целом объекты, извлеченные из разных источников, не будут идентичными. Если вы хотите сравнить равенство, просто используйте ==.

Python хранит целые числа в диапазоне -5 - 256 в интерпретаторе: он имеет пул целочисленных объектов, из которых эти целые числа возвращаются. Вот почему эти объекты одинаковы: (0-5) и -5, но не (0-6) и -6, поскольку они создаются на месте.

Вот источник в исходном коде CPython:

#define NSMALLPOSINTS           257
#define NSMALLNEGINTS           5
static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];

(просмотр исходного кода CPython: /trunk/Objects/intobject.c). Исходный код содержит следующий комментарий:

/* References to small integers are saved in this array so that they
   can be shared.
   The integers that are saved are those in the range
   -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive).
*/

Оператор is будет затем сравнивать они (-5) равны, потому что это один и тот же объект (одно и то же место в памяти), но два других новых целых числа (-6) будут находиться в разных местах памяти (и тогда is не вернет True). Обратите внимание, что 257 В приведенном выше исходном коде является для положительных целых чисел таким образом, что 0 - 256 (включительно).

(Источник )

Это не ошибка. is не является тестом на равенство. == даст ожидаемые результаты.

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

Это происходит потому, что CPython кэширует некоторые маленькие целые числа и маленькие строки и дает каждому экземпляру этого объекта один и тот же id().

(0-5) и -5 имеет то же значение для id(), что не верно для 0-6 и -6

>>> id((0-6))
12064324
>>> id((-6))
12064276
>>> id((0-5))
10022392
>>> id((-5))
10022392

Аналогично для строк:

>>> x = 'abc'
>>> y = 'abc'
>>> x is y
True
>>> x = 'a little big string'
>>> y = 'a little big string'
>>> x is y
False

Для получения более подробной информации о кэшировании строк, прочитайте: is оператор ведет себя по-разному при сравнении строк с пробелами