Две переменные в Python имеют одинаковый идентификатор, но не списки или кортежи

Две переменные в Python имеют одинаковыеid:

a = 10
b = 10
a is b
>>> True

Если я возьму дваlists:

a = [1, 2, 3]
b = [1, 2, 3]
a is b
>>> False

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

Так что теперь, согласно его ответу, кортежи должны иметь одинаковые идентификаторы, что означает:

a = (1, 2, 3)
b = (1, 2, 3)
a is b
>>> False

В идеале, поскольку кортежи не являются изменяемыми, они должны возвращатьсяTrue, но это возвращаетсяFalse!

Какое объяснение?

 dmitryro04 июл. 2016 г., 19:23
Вы должны различать переменные и объекты (списки и кортежи) - когда вы сравниваете два таких объекта, вы сравниваете их адреса памяти, которые различаются, несмотря на наличие одинаковых элементов списка и кортежа.
 Ram Vallury04 июл. 2016 г., 19:36
Спасибо @JacquesGaudin! Это делает некоторое понимание для меня сейчас.
 Jim Fasarakis Hilliard16 авг. 2016 г., 11:39
Я снова открываю это, потому что цель dup не затрагивает суть этого вопроса, а именно, влияет ли изменчивость на идентичности.
 Jacques Gaudin04 июл. 2016 г., 19:28
Я думаю, что вы неправильно поняли ответ, на который ссылаетесь. Разные неизменяемые объекты имеют разные идентификаторы. Но для целых чисел <256 (на большинстве интерпретаторов) значение предварительно загружается в память, и поэтому в вашем первом примере a является b
 Bakuriu05 июл. 2016 г., 09:28
Выполнена ли такая оптимизация или нет?не гарантировано, Вы должны просто перестать думать об этом, иногдаis вернусьTrue а другие времена нет. Если вы хотите быть уверены, что он вернетсяTrue просто сделайте:b = a или жеb = tuple(a)  (tuple Вызов возвратит ссылку на аргумент, если передан кортеж в качестве параметра).

Ответы на вопрос(4)

a а такжеb сохраняют свои старые ссылки (ID) назад, когда мы присваиваем им более старые значения. (НО ЭТО НЕ БУДЕТ ОБРАЩАТЬСЯ С СПИСКАМИ, ПОЧЕМУ ОНИ МОГУТ УКАЗАТЬСЯ)

Первоначальноa а такжеb имеют одинаковые значения ((1,2)), но имеют разные идентификаторы. После изменения их значений, когда мы переназначаем значение (1,2) наa а такжеbтеперь они ссылаются на свои собственные идентификаторы (88264264 и 88283400 соответственно).

>>> a = (1,2)
>>> b = (1,2)
>>> a , b
((1, 2), (1, 2))
>>> id(a)
88264264
>>> id(b)
88283400
>>> a = (3,4)
>>> b = (3,4)
>>> id(a)
88280008
>>> id(b)
88264328
>>> a = (1,2)
>>> b = (1,2)
>>> id(a)
88264264
>>> id(b)
88283400
>>> a , b
((1, 2), (1, 2))
>>> id(a) , id(b)
(88264264, 88283400)
>>> 

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

Неизменный!= тот же объект.*

Неизменяемый объект - это просто объект, состояние которого нельзя изменить; и это все.Когда новый объект создан,ему будет присвоен новый адрес. Таким образом, проверка того, равны ли адресаis вернусьFalse.

Дело в том, что1 is 1 или же"a" is "a" возвращаетсяTrue связано сцелочисленное кеширование и строкаинтернирование в исполнении Python, поэтому не позволяйте этому сбить вас с толку; это не связано с тем, что рассматриваемые объекты являются изменяемыми / неизменяемыми.

* Пустые неизменяемые объектыссылаются на один и тот же объект и ихisness действительно возвращает true, однако это особый случай реализации.

Решение Вопроса

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

Однако для оптимизации (в основном) есть некоторые исключения для маленьких целых чисел (от -5 до 256) и маленьких строк (интернированные строки, особой длины (обычно менее 20 символов)), которые являются синглетонами и имеют одинаковыеid (на самом деле один объект с несколькими указателями). Вы можете проверить этот факт следующим образом:

>>> 30 is 20 + 10
True
>>> 
>>> 300 is 200 + 100
False
>>> 'aa' * 2 is 'a' * 4
True
>>> 'aa' * 20 is 'a' * 40
False

И для пользовательского объекта:

>>> class A:
...    pass
... 
>>> A() is A() # Every time you create an instance you'll have a new instance with new identity
False

Также обратите внимание, чтоis Оператор проверит идентичность объекта, а не значение. Если вы хотите проверить значение, которое вы должны использовать==:

>>> 300 == 3*100
True

А поскольку для кортежей (других типов) такого правила не существует, если вы определите два одинаковых кортежа любого размера, они получат свои собственные идентификаторы:

>>> a = (1,)
>>> b = (1,)
>>>
>>> a is b
False

И обратите внимание, что факт одноэлементных целых чисел и внутренних строк верен, даже если вы определяете их в изменяемых и неизменных объектах:

>>> a = (100, 700, 400)
>>>
>>> b = (100, 700, 400)
>>>
>>> a[0] is b[0]
True
>>> a[1] is b[1]
False
 Kasrâmvd04 июл. 2016 г., 19:44
@Ram Почему вы думаете, что он должен возвращать True, это 2 отдельных объекта (целых числа), но с одинаковым значением (не id). И обратите внимание, что их не менее 256.
 stillanoob05 окт. 2018 г., 15:55
@ Kasrâmvd Извините за беспорядок. Пусть будет классA с методом экземпляраfoo, Мой вопрос, еслиis Оператор проверяет личность, то почемуA.foo is A.foo оцениваетFalse когдаid(A.foo) по-видимому, возвращает одно и то же значение каждый раз?
 Amin Negm-Awad05 июл. 2016 г., 08:56
Тем не менее, следует различать эти две модели как твинтон или мультитон, а не синглтон.en.wikipedia.org/wiki/Multiton_pattern
 Ram Vallury04 июл. 2016 г., 19:48
да согласен. Я думаю, что только целые числа <256 вернут ids () true. любое целое число больше 256 в интерпретаторе Python будет иметь свое собственное пространство идентификаторов, значения будут одинаковыми.
 stillanoob05 окт. 2018 г., 11:22
@ Kasrâmvd "обратите внимание, что оператор is будет проверять идентичность объекта" - ну, как насчет этого -exec("class A:\n\tdef foo(): pass\na=A()\nassert id(a.foo) == id(a.foo.__get__(a))\nassert a.foo is not a.foo.__get__(a)")?
 Ram Vallury04 июл. 2016 г., 19:39
в последнем упомянутом примере (из кортежей): a [1] is b [1] должно быть True, почему он вернул False?
 Kasrâmvd05 окт. 2018 г., 19:05
@stillanoob Потому что каждый раз, когда вы делаетеA.foo Вы создаете другой объект. Прочитайте мой ответ здесьstackoverflow.com/questions/27069448/... Также обратите внимание, что не используйте интерактивную оболочку для внутренних тестов. Она может ввести вас в заблуждение, потому что ее коды компилируются на каждом входе.
 Kasrâmvd05 окт. 2018 г., 13:05
@stillanoob Да, как насчет этого? :)) Ваш код представляет собой беспорядок различных пространств имен и объектов, которые создаются во время выполнения. Пожалуйста, объясните, в чем здесь проблема или как вопрос об этом.
 cat05 июл. 2016 г., 06:57
Тот факт, что все маленькие 8-битные числа ссылаются на одни и те же объекты в памяти, является деталью реализации CPython и на него не следует полагаться по какой-либо причине.
 Bakuriu05 июл. 2016 г., 09:31
@Ram Я полагаю, вы видите ситуацию с неправильной точки зрения. Вы должны спросить себя, почему это возвращаетсяTrue заa[0] а такжеb[0], а не почему это возвращаетFalse заa[1] а такжеb[1], Увидетьэтот связанный ответ мой если вы хотите больше подробностей об этом.

Посмотрите на этот код:

>>> a = (1, 2, 3)
>>> b = (1, 2, 3)
>>> c = a
>>> id(a)
178153080L
>>> id(b)
178098040L
>>> id(c)
178153080L

Чтобы выяснить, почемуa is c оценивается какTrue в то время какa is b доходностьFalse Я настоятельно рекомендую пошагово запустить приведенный выше фрагмент вИнтернет Python Tutor, Графическое представление объектов в памяти предоставит вам более глубокое понимание этой проблемы (я прилагаю скриншот).

Ваш ответ на вопрос