Dans un commentaire sur cette question , j'ai vu une déclaration qui recommandait d'utiliser
result is not None
contre
result != None
Je me demandais quelle est la différence et pourquoi l'une pourrait être recommandée par rapport à l'autre?
Dans un commentaire sur cette question , j'ai vu une déclaration qui recommandait d'utiliser
result is not None
contre
result != None
Je me demandais quelle est la différence et pourquoi l'une pourrait être recommandée par rapport à l'autre?
Réponses:
==
est un test d'égalité . Il vérifie si le côté droit et le côté gauche sont des objets égaux (selon leur __eq__
ou leurs __cmp__
méthodes.)
is
est un test d'identité . Il vérifie si le côté droit et le côté gauche sont le même objet. Aucun appel de méthode n'est effectué, les objets ne peuvent pas influencer l' is
opération.
Vous utilisez is
(et is not
) pour les singletons, par exemple None
, lorsque vous ne vous souciez pas des objets qui pourraient prétendre être None
ou lorsque vous souhaitez vous protéger contre la rupture d'objets lors de la comparaison None
.
None
a peu de méthodes et presque aucun attribut. Si votre __eq__
test attendait une méthode ou un attribut, il pourrait casser. def __eq__( self, other ): return self.size == other.size
. Par exemple, se cassera s'il other
se trouve None
.
is
est comme Java ==
. Python ==
est comme Java .equals()
. Bien sûr, cela n'aide que si vous connaissez Java.
is
c'est comme ===
(très égal), et inversement is not
c'est comme !==
(pas exactement égal).
is not
qu'un seul opérateur ou est-ce simplement en train de nier le résultat de l' is
intérieur comme not foo is bar
?
Tout d'abord, permettez-moi de passer en revue quelques termes. Si vous souhaitez simplement obtenir une réponse à votre question, faites défiler la page jusqu'à "Répondre à votre question".
Identité de l'objet : lorsque vous créez un objet, vous pouvez l'affecter à une variable. Vous pouvez ensuite également l'affecter à une autre variable. Et un autre.
>>> button = Button()
>>> cancel = button
>>> close = button
>>> dismiss = button
>>> print(cancel is close)
True
Dans ce cas, cancel
, close
et dismiss
tous se réfèrent au même objet en mémoire. Vous avez créé un seul Button
objet et les trois variables font référence à cet objet unique. Nous disons que cancel
, close
et dismiss
tous se réfèrent à des objets identiques ; c'est-à-dire qu'ils se réfèrent à un seul objet.
Égalité d'objet : lorsque vous comparez deux objets, vous ne vous souciez généralement pas qu'il se réfère exactement au même objet en mémoire. Avec l'égalité des objets, vous pouvez définir vos propres règles de comparaison entre deux objets. Lorsque vous écrivez if a == b:
, vous dites essentiellement if a.__eq__(b):
. Cela vous permet de définir une __eq__
méthode a
afin que vous puissiez utiliser votre propre logique de comparaison.
Justification: deux objets ont exactement les mêmes données, mais ne sont pas identiques. (Ils ne sont pas le même objet en mémoire.) Exemple: chaînes
>>> greeting = "It's a beautiful day in the neighbourhood."
>>> a = unicode(greeting)
>>> b = unicode(greeting)
>>> a is b
False
>>> a == b
True
Remarque: j'utilise des chaînes unicode ici car Python est suffisamment intelligent pour réutiliser des chaînes régulières sans en créer de nouvelles en mémoire.
Ici, j'ai deux chaînes unicode, a
et b
. Ils ont exactement le même contenu, mais ils ne sont pas le même objet en mémoire. Cependant, lorsque nous les comparons, nous voulons qu'ils se comparent égaux. Ce qui se passe ici, c'est que l'objet unicode a implémenté la __eq__
méthode.
class unicode(object):
# ...
def __eq__(self, other):
if len(self) != len(other):
return False
for i, j in zip(self, other):
if i != j:
return False
return True
Remarque: __eq__
on unicode
est définitivement implémenté plus efficacement que cela.
Justification: Deux objets ont des données différentes, mais sont considérés comme le même objet si certaines données clés sont identiques. Exemple: la plupart des types de données de modèle
>>> import datetime
>>> a = Monitor()
>>> a.make = "Dell"
>>> a.model = "E770s"
>>> a.owner = "Bob Jones"
>>> a.warranty_expiration = datetime.date(2030, 12, 31)
>>> b = Monitor()
>>> b.make = "Dell"
>>> b.model = "E770s"
>>> b.owner = "Sam Johnson"
>>> b.warranty_expiration = datetime.date(2005, 8, 22)
>>> a is b
False
>>> a == b
True
Ici, j'ai deux moniteurs Dell a
et b
. Ils ont la même marque et le même modèle. Cependant, ils n'ont ni les mêmes données ni le même objet en mémoire. Cependant, lorsque nous les comparons, nous voulons qu'ils se comparent égaux. Ce qui se passe ici, c'est que l'objet Monitor a implémenté la __eq__
méthode.
class Monitor(object):
# ...
def __eq__(self, other):
return self.make == other.make and self.model == other.model
Lorsque vous comparez à None
, utilisez toujours is not
. Aucun n'est un singleton en Python - il n'y en a jamais qu'une seule en mémoire.
En comparant l' identité , cela peut être effectué très rapidement. Python vérifie si l'objet auquel vous faites référence a la même adresse mémoire que l'objet global None - une comparaison très, très rapide de deux nombres.
En comparant l' égalité , Python doit vérifier si votre objet a une __eq__
méthode. Si ce n'est pas le cas, il examine chaque superclasse à la recherche d'une __eq__
méthode. S'il en trouve un, Python l'appelle. Cela est particulièrement mauvais si la __eq__
méthode est lente et ne revient pas immédiatement lorsqu'elle remarque que l'autre objet l'est None
.
N'avez-vous pas mis en œuvre __eq__
? Ensuite, Python trouvera probablement la __eq__
méthode object
et l'utilisera à la place - qui vérifie simplement l'identité de l'objet de toute façon.
Lorsque vous comparez la plupart des autres choses en Python, vous utiliserez !=
.
Considérer ce qui suit:
class Bad(object):
def __eq__(self, other):
return True
c = Bad()
c is None # False, equivalent to id(c) == id(None)
c == None # True, equivalent to c.__eq__(None)
None
est un singleton, donc la comparaison d'identité fonctionnera toujours, alors qu'un objet peut simuler la comparaison d'égalité via .__eq__()
.
None
, mais un comportement incorrect concernant None
pourrait se produire comme effet secondaire de la mise en œuvre de l'égalité contre d'autres types. Ce ne sont pas tant des implications de sécurité que des implications de justesse.
>>> () est () Vrai >>> 1 est 1 Vrai >>> (1,) == (1,) Vrai >>> (1,) est (1,) Faux >>> a = (1,) >>> b = a >>> a est b Vrai
Certains objets sont singletons, et donc is
avec eux est équivalent à ==
. La plupart ne le sont pas.
()
et 1
ne sont pas intrinsèquement singletons.
-NSMALLNEGINTS <= n <= NSMALLPOSINTS
) et les tuples vides sont des singletons. En effet, ce n'est ni documenté ni garanti, mais il est peu probable qu'il change.