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 était la différence et pourquoi l'une d'elles pouvait être recommandée plutôt que l'autre?
==
est un test d'égalité. Il vérifie si les côtés droit et gauche sont des objets égaux (en fonction de leurs méthodes __eq__
ou __cmp__
.)
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'opération is
.
Vous utilisez is
(et is not
) pour des singletons, comme None
, où vous ne vous souciez pas des objets pouvant prétendre être None
ou de l'endroit souhaité. protège contre la casse d'objets lors de la comparaison avec None
.
Tout d'abord, laissez-moi passer en revue quelques termes. Si vous souhaitez seulement que votre question soit répondue, faites défiler jusqu'à "Répondre à votre question".
Identité d'objet: Lorsque vous créez un objet, vous pouvez l'affecter à une variable. Vous pouvez alors aussi 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
désignent tous le même objet en mémoire. Vous n'avez créé qu'un seul objet Button
et les trois variables font référence à cet objet. Nous disons que cancel
, close
et dismiss
désignent tous 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 au même objet exact en mémoire . Avec l'égalité des objets, vous pouvez définir vos propres règles pour la comparaison de deux objets. Lorsque vous écrivez if a == b:
, vous dites essentiellement if a.__eq__(b):
. Cela vous permet de définir une méthode __eq__
sur 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 standard 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 de manière égale. Ce qui se passe ici, c'est que l'objet unicode a implémenté la méthode __eq__
.
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__
sur unicode
est définitivement mis en œuvre 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 de manière égale. Ce qui se passe ici, c'est que l'objet Monitor a implémenté la méthode __eq__
.
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 dans Python - il n'y a jamais qu'une seule instance en mémoire.
En comparant 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 rechercher si votre objet dispose d'une méthode __eq__
. Si ce n'est pas le cas, il examine chaque super-classe à la recherche d'une méthode __eq__
. S'il en trouve un, Python l'appelle. Cela est particulièrement grave si la méthode __eq__
est lente et ne retourne pas immédiatement lorsqu'elle remarque que l'autre objet est None
.
N'avez-vous pas implémenté __eq__
? Ensuite, Python trouvera probablement la méthode __eq__
sur object
et l'utilisera à la place, qui vérifie simplement l'identité de l'objet.
Lorsque vous comparerez la plupart des 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, la comparaison d'identité fonctionnera donc toujours, alors qu'un objet peut simuler la comparaison d'égalité via .__eq__()
.
>>> () est () Vrai >>> 1 est 1 Vrai >>> (1,) == (1,) Vrai >>> (1,) est (1,) Faux >>> a = (1,) >>> b = a >>> a est b Vrai
Certains objets sont des singletons, et donc is
avec eux est équivalent à ==
. La plupart ne le sont pas.