web-dev-qa-db-fra.com

Deux variables en Python ont le même identifiant, mais pas les listes ni les tuples

Deux variables en Python ont la même id:

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

Si je prends deux lists:

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

selon ce lien Senderle a répondu que les références d'objets immuables ont le même identifiant et que les objets mutables comme les listes ont des identifiants différents.

Alors maintenant, selon sa réponse, les tuples devraient avoir les mêmes identifiants - ce qui signifie:

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

Idéalement, comme les n-uplets ne sont pas mutables, il devrait retourner True, mais il retourne False!

Quelle est l'explication?

41
Ram Vallury

Les objets immuables n'ont pas la même id et, en réalité, ceci n'est pas vrai pour tout type d'objets que vous définissez séparément. En règle générale, chaque fois que vous définissez un objet en Python, vous créez un nouvel objet avec une nouvelle identité.

Cependant, dans un souci d’optimisation (la plupart du temps), il existe quelques exceptions pour les petits entiers (entre -5 et 256) et les petites chaînes (chaînes internes, avec une longueur spéciale (généralement moins de 20 caractères)) qui sont singletons et ont la même id (en fait, un objet avec plusieurs pointeurs). Vous pouvez vérifier ce fait comme suit:

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

Et pour un objet personnalisé:

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

Notez également que l'opérateur is vérifiera l'identité de l'objet et non sa valeur. Si vous voulez vérifier la valeur, vous devez utiliser ==:

>>> 300 == 3*100
True

Et comme il n’existe pas de règle de ce type pour les n-uplets (autres types), si vous définissez les deux mêmes n-uplets quelle que soit leur taille, ils obtiendront leurs propres identifiants:

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

Et notez que le fait de singleton entiers et de chaînes interned est vrai même lorsque vous les définissez dans des objets mutables et immuables:

>>> a = (100, 700, 400)
>>>
>>> b = (100, 700, 400)
>>>
>>> a[0] is b[0]
True
>>> a[1] is b[1]
False
55
Kasrâmvd

Immuable != même objet.*

Un objet immuable est simplement un objet dont l'état ne peut pas être modifié; et c'est tout. Lorsqu'un nouvel objet est créé, une nouvelle adresse lui sera attribuée. Ainsi, vérifier si les adresses sont égales avec is retournera False

Le fait que 1 is 1 ou "a" is "a" renvoie True est dû à la mise en cache des entiers et à la chaîne interning effectuée par Python, ne la laissez pas vous dérouter; il n'est pas lié aux objets en question étant mutables/immuables.


* Les objets immuables vides font référence au même objet et leur isness renvoie true, il s'agit toutefois d'un cas spécifique à l'implémentation.

20

Jetez un oeil à ce code:

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

Afin de comprendre pourquoi a is c est évalué en tant que True alors que a is b donne False, je vous recommande vivement d'exécuter l'extrait étape par étape ci-dessus dans Python Online Tutor . La représentation graphique des objets en mémoire vous permettra de mieux comprendre ce problème (je joins une capture d'écran).

 enter image description here

15
Tonechas

Vérifiez ci-dessous le code .. Tupils a et b conservent leurs anciennes références (ID) lorsque nous avons affecté leurs anciennes valeurs. (MAIS CELA NE SERAIT PAS LE CAS DES LISTES COMME ILS SONT MUTABLES)

Initialement, a et b ont les mêmes valeurs ((1,2)), mais ils ont des ID de différence. Après modification de leurs valeurs, lorsque nous réaffectons la valeur (1,2) à a et b, ils se réfèrent maintenant à LEUR PROPRE identificateurs identiques (88264264 et 88283400 respectivement). 

>>> 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)
>>> 

** Vérifiez le lien Pourquoi les n-uplets n'ont-ils pas le même identifiant si on leur attribue les mêmes valeurs? aussi après avoir lu ceci. Un autre cas a également été discuté ici. 

0
AKSHAY KUMAR