Почему (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 ответа:
Все целые числа от -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
(включительно).(Источник )
Это не ошибка.
Техническая причина такого поведения заключается в том, что реализация Python может свободно обрабатывать различные экземпляры одного и того же постоянного значения либо как один и тот же объект, либо как разные объекты. Реализация Python, которую вы используете, выбирает, чтобы некоторые небольшие константы совместно использовали один и тот же объект для экономии памяти. Вы не можете полагаться на то, что это поведение будет одинаковым от версии к версии или поперек различные реализации Python.is
не является тестом на равенство.==
даст ожидаемые результаты.
Это происходит потому, что 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
оператор ведет себя по-разному при сравнении строк с пробелами