124 votes

Comprendre l'opérateur "is

El is ne correspond pas aux valeurs des variables, mais l'opérateur instances elles-mêmes.

Qu'est-ce que cela signifie vraiment ?

J'ai déclaré deux variables nommées x y y en affectant les mêmes valeurs aux deux variables, mais il renvoie un résultat faux lorsque j'utilise la fonction is opérateur.

J'ai besoin d'une clarification. Voici mon code.

x = [1, 2, 3]
y = [1, 2, 3]

print(x is y)  # It prints false!

204voto

Martijn Pieters Points 271458

Vous avez mal compris ce que le is les tests des opérateurs. Il teste si deux variables pointent le même objet mais pas si deux variables ont la même valeur.

D'après la documentation relative au is opérateur :

Les opérateurs is y is not test d'identité d'objet : x is y est vrai si et seulement si x y y sont le même objet.

Utilisez le == à la place :

print(x == y)

Cette impression True . x y y sont deux séparé listes :

x[0] = 4
print(y)  # prints [1, 2, 3]
print(x == y)   # prints False

Si vous utilisez le id() fonction vous verrez que x y y ont des identifiants différents :

>>> id(x)
4401064560
>>> id(y)
4401098192

mais si vous deviez attribuer y a x alors les deux désignent le même objet :

>>> x = y
>>> id(x)
4401064560
>>> id(y)
4401064560
>>> x is y
True

y is montre que les deux sont le même objet, il renvoie True .

Rappelez-vous qu'en Python, les noms ne sont que des étiquettes faisant référence à des valeurs ; vous pouvez faire pointer plusieurs noms vers le même objet. is vous indique si deux noms pointent vers un seul et même objet. == vous indique si deux noms font référence à des objets qui ont la même valeur.

69voto

abarnert Points 94246

Un autre duplicata demandait pourquoi deux cordes égales ne sont généralement pas identiques, ce qui n'est pas vraiment répondu ici :

>>> x = 'a' 
>>> x += 'bc'
>>> y = 'abc'
>>> x == y
True
>>> x is y
False

Alors, pourquoi ce n'est pas la même chaîne ? Surtout si l'on tient compte de ceci :

>>> z = 'abc'
>>> w = 'abc'
>>> z is w
True

Remettons la deuxième partie à plus tard. Comment la première partie pourrait-elle être vraie ?

L'interpréteur devrait disposer d'une "table d'internage", une table de correspondance entre les valeurs des chaînes de caractères et les objets chaîne de caractères, de sorte qu'à chaque fois que vous essayez de créer une nouvelle chaîne de caractères avec le contenu 'abc' vous récupérez le même objet. Wikipedia propose une discussion plus détaillée sur le fonctionnement des stages.

Et Python a une table d'internage de chaînes de caractères ; vous pouvez internaliser manuellement des chaînes de caractères avec la fonction sys.intern méthode.

En fait, Python est autorisé pour internaliser automatiquement tout type immuable, mais pas requis pour le faire. Des implémentations différentes interneront des valeurs différentes.

CPython (l'implémentation que vous utilisez si vous ne savez pas quelle implémentation vous utilisez) internalise automatiquement les petits entiers et certains singletons spéciaux tels que False mais pas les chaînes de caractères (ni les grands entiers, ni les petits tuples, ni rien d'autre). Vous pouvez le constater assez facilement :

>>> a = 0
>>> a += 1
>>> b = 1
>>> a is b
True
>>> a = False
>>> a = not a
>>> b = True
a is b
True
>>> a = 1000
>>> a += 1
>>> b = 1001
>>> a is b
False

OK, mais pourquoi z y w identique ?

Ce n'est pas l'interpréteur qui s'interpose automatiquement, c'est le compilateur qui plie les valeurs.

Si la même chaîne de caractères en temps de compilation apparaît deux fois dans le même module (ce que cela signifie exactement est difficile à définir - ce n'est pas la même chose qu'une chaîne littérale, parce que r'abc' , 'abc' y 'a' 'b' 'c' sont tous des littéraux différents mais la même chaîne - mais facile à comprendre intuitivement), le compilateur ne créera qu'une seule instance de la chaîne, avec deux références.

En fait, le compilateur peut même aller plus loin : 'ab' + 'c' peut être converti en 'abc' par l'optimiseur, auquel cas elle peut être repliée avec une 'abc' constant dans le même module.

Encore une fois, c'est quelque chose que Python est autorisé à faire mais n'est pas obligé de le faire. Mais dans ce cas, CPython plie toujours les petites chaînes de caractères (et aussi, par exemple, les petits tuples). (Bien que le compilateur statement-by-statement de l'interpréteur interactif n'exécute pas la même optimisation que le compilateur module-at-a-time, vous ne verrez donc pas exactement les mêmes résultats de manière interactive).


Alors, que faire en tant que programmeur ?

Eh bien rien. Vous n'avez presque jamais de raison de vous soucier de savoir si deux valeurs immuables sont identiques. Si vous voulez savoir quand vous pouvez utiliser a is b au lieu de a == b vous posez la mauvaise question. Il suffit de toujours utiliser a == b sauf dans deux cas :

  • Pour des comparaisons plus lisibles avec les valeurs singleton comme x is None .
  • Pour les valeurs mutables, lorsque vous avez besoin de savoir si la mutation x aura une incidence sur le y .

8voto

Mark Ransom Points 132545

is ne renvoie vrai que s'il s'agit du même objet. S'ils étaient identiques, une modification apportée à l'un se répercuterait sur l'autre. Voici un exemple de la différence.

>>> x = [1, 2, 3]
>>> y = [1, 2, 3]
>>> print x is y
False
>>> z = y
>>> print y is z
True
>>> print x is z
False
>>> y[0] = 5
>>> print z
[5, 2, 3]

8voto

Amadan Points 41944

Poussé par un question de duplication cette analogie pourrait fonctionner :

# - Darling, I want some pudding!
# - There is some in the fridge.

pudding_to_eat = fridge_pudding
pudding_to_eat is fridge_pudding
# => True

# - Honey, what's with all the dirty dishes?
# - I wanted to eat pudding so I made some. Sorry about the mess, Darling.
# - But there was already some in the fridge.

pudding_to_eat = make_pudding(ingredients)
pudding_to_eat is fridge_pudding
# => False

6voto

gixxer Points 401

is y is not sont les deux opérateurs d'identité en Python. is ne compare pas les valeurs des variables, mais compare les identités des variables. Considérez ceci :

>>> a = [1,2,3]
>>> b = [1,2,3]
>>> hex(id(a))
'0x1079b1440'
>>> hex(id(b))
'0x107960878'
>>> a is b
False
>>> a == b
True
>>>

L'exemple ci-dessus montre que l'identité (qui peut aussi être l'adresse mémoire en Cpython) est différente dans les deux cas a y b (même si leurs valeurs sont les mêmes). C'est pourquoi lorsque vous dites a is b il renvoie faux en raison de l'incompatibilité des identités des deux opérandes. Cependant, lorsque vous dites a == b il renvoie la réponse vraie parce que le == L'opération vérifie uniquement si les deux opérandes ont la même valeur.

Exemple intéressant (pour la note supplémentaire) :

>>> del a
>>> del b
>>> a = 132
>>> b = 132
>>> hex(id(a))
'0x7faa2b609738'
>>> hex(id(b))
'0x7faa2b609738'
>>> a is b
True
>>> a == b
True
>>>

Dans l'exemple ci-dessus, même si a y b sont deux variables différentes, a is b a retourné True . Cela s'explique par le fait que le type de a es int qui est un objet immuable. Donc python (je suppose que pour économiser de la mémoire) a alloué le même objet à b lorsqu'il a été créé avec la même valeur. Donc, dans ce cas, les identités des variables correspondaient et a is b s'est avéré être True .

Cela s'applique à tous les objets immuables :

>>> del a
>>> del b
>>> a = "asd"
>>> b = "asd"
>>> hex(id(a))
'0x1079b05a8'
>>> hex(id(b))
'0x1079b05a8'
>>> a is b
True
>>> a == b
True
>>>

J'espère que cela vous aidera.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X