Y a-t-il une différence entre ==
et is
en Python?
Oui, ils ont une différence très importante.
==
: vérifier l'égalité - la sémantique est que les objets équivalents (qui ne sont pas nécessairement le même objet) seront testés comme égaux. Comme le dit la documentation :
Les opérateurs <,>, ==,> =, <= et! = Comparent les valeurs de deux objets.
is
: vérifier l'identité - la sémantique est que l'objet (tel qu'il est conservé en mémoire) est l'objet. Encore une fois, la documentation dit :
Les opérateurs is
et is not
testent l'identité de l'objet: x is y
est vrai si et seulement si x
et y
sont le même objet. L'identité de l'objet est déterminée à l'aide de la id()
fonction. x is not y
donne la valeur de vérité inverse.
Ainsi, la vérification d'identité est identique à la vérification de l'égalité des ID des objets. C'est,
a is b
est le même que:
id(a) == id(b)
où id
est la fonction intégrée qui renvoie un entier qui "est garanti unique parmi les objets existants simultanément" (voir help(id)
) et où a
et b
tout objet arbitraire.
Autres instructions d'utilisation
Vous devez utiliser ces comparaisons pour leur sémantique. Utilisez is
pour vérifier l'identité et ==
pour vérifier l'égalité.
Donc, en général, nous utilisons is
pour vérifier l'identité. Ceci est généralement utile lorsque nous recherchons un objet qui ne devrait exister qu'une seule fois en mémoire, appelé "singleton" dans la documentation.
Les cas d'utilisation is
incluent:
None
- valeurs enum (lors de l'utilisation d'énumérations à partir du module enum)
- généralement des modules
- généralement des objets de classe résultant de définitions de classe
- généralement des objets fonction résultant de définitions de fonctions
- toute autre chose qui ne devrait exister qu'une seule fois dans la mémoire (tous les singletons, en général)
- un objet spécifique que vous voulez par identité
Les cas d'utilisation habituels ==
incluent:
- nombres, y compris des entiers
- cordes
- listes
- ensembles
- dictionnaires
- objets mutables personnalisés
- d'autres objets immuables intégrés, dans la plupart des cas
Le cas d'usage général, encore une fois, car ==
, est l'objet que vous voulez peut - être pas le même objet, au lieu , il peut être un équivalent d' un
PEP 8 directions
PEP 8, le guide de style Python officiel pour la bibliothèque standard mentionne également deux cas d'utilisation pouris
:
Les comparaisons avec des singletons comme None
devraient toujours être faites avec is
ou
is not
, jamais avec les opérateurs d'égalité.
Aussi, méfiez-vous d'écrire if x
quand vous voulez vraiment dire if x is not None
- par exemple lorsque vous testez si une variable ou un argument par défaut a None
été défini sur une autre valeur. L'autre valeur peut avoir un type (tel qu'un conteneur) qui pourrait être faux dans un contexte booléen!
Déduire l'égalité de l'identité
Si is
c'est vrai, l'égalité peut généralement être déduite - logiquement, si un objet est lui-même, il doit alors être testé comme équivalent à lui-même.
Dans la plupart des cas, cette logique est vraie, mais elle repose sur la mise en œuvre de la __eq__
méthode spéciale. Comme le disent les docs ,
Le comportement par défaut pour la comparaison d'égalité ( ==
et !=
) est basé sur l'identité des objets. Par conséquent, la comparaison d'égalité des instances avec la même identité entraîne l'égalité et la comparaison d'égalité des instances avec des identités différentes entraîne l'inégalité. Une motivation pour ce comportement par défaut est le désir que tous les objets soient réflexifs (c'est-à-dire que x est y implique x == y).
et dans un souci de cohérence, recommande:
La comparaison de l'égalité doit être réflexive. En d'autres termes, les objets identiques doivent comparer égaux:
x is y
implique x == y
Nous pouvons voir que c'est le comportement par défaut pour les objets personnalisés:
>>> class Object(object): pass
>>> obj = Object()
>>> obj2 = Object()
>>> obj == obj, obj is obj
(True, True)
>>> obj == obj2, obj is obj2
(False, False)
La contrapositive est également généralement vraie - si quelque chose est différent, vous pouvez généralement déduire qu'il ne s'agit pas du même objet.
Étant donné que les tests d'égalité peuvent être personnalisés, cette inférence n'est pas toujours vraie pour tous les types.
Une exception
Une exception notable est nan
- il teste toujours comme différent de lui-même:
>>> nan = float('nan')
>>> nan
nan
>>> nan is nan
True
>>> nan == nan # !!!!!
False
La vérification de l'identité peut être beaucoup plus rapide que la vérification de l'égalité (ce qui peut nécessiter une vérification récursive des membres).
Mais il ne peut pas être substitué à l'égalité où vous pouvez trouver plus d'un objet comme équivalent.
Notez que la comparaison de l'égalité des listes et des tuples supposera que l'identité des objets est égale (car il s'agit d'une vérification rapide). Cela peut créer des contradictions si la logique est incohérente - comme c'est le cas pour nan
:
>>> [nan] == [nan]
True
>>> (nan,) == (nan,)
True
Un récit édifiant:
La question tente d'utiliser is
pour comparer des entiers. Vous ne devez pas supposer qu'une instance d'un entier est la même instance que celle obtenue par une autre référence. Cette histoire explique pourquoi.
Un commentateur avait du code qui reposait sur le fait que les petits entiers (-5 à 256 inclus) sont des singletons en Python, au lieu de vérifier l'égalité.
Wow, cela peut conduire à des bugs insidieux. J'avais un code qui vérifiait si a est b, qui fonctionnait comme je le voulais parce que a et b sont généralement de petits nombres. Le bogue ne s'est produit qu'aujourd'hui, après six mois de production, car a et b étaient finalement suffisamment gros pour ne pas être mis en cache. - gwg
Cela a fonctionné dans le développement. Il a peut-être réussi certains tests.
Et cela a fonctionné en production - jusqu'à ce que le code vérifie un entier supérieur à 256, moment auquel il a échoué en production.
Il s'agit d'un échec de production qui aurait pu être détecté dans la révision du code ou éventuellement avec un vérificateur de style.
Permettez-moi de souligner: ne pas utiliser is
pour comparer des entiers.
echo 'import sys;tt=sys.argv[1];print(tt is "foo", tt == "foo", id(tt)==id("foo"))'| python3 - foo
sortie:False True False
.