Y a-t-il une différence entre «foo is None» et «foo == None»?

217

Y a-t-il une différence entre:

if foo is None: pass

et

if foo == None: pass

La convention que j'ai vue dans la plupart du code Python (et le code que j'écris moi-même) est la première, mais j'ai récemment rencontré du code qui utilise la seconde. Aucun n'est une instance (et la seule instance, IIRC) de NoneType, donc cela ne devrait pas avoir d'importance, non? Y a-t-il des circonstances dans lesquelles cela pourrait se produire?

Joe Shaw
la source

Réponses:

253

isrenvoie toujours Trues'il compare la même instance d'objet

Alors que ==est finalement déterminé par la __eq__()méthode

c'est à dire


>>> class Foo(object):
       def __eq__(self, other):
           return True

>>> f = Foo()
>>> f == None
True
>>> f is None
False
Brendan
la source
51
Vous voudrez peut-être ajouter que None est un singleton, donc "None is None" est toujours True.
e-satis
43
Et vous voudrez peut-être ajouter que l' isopérateur ne peut pas être personnalisé (surchargé par une classe définie par l'utilisateur).
martineau
@study La méthode __eq__(self)est une méthode intégrée spéciale qui détermine comment elle ==est gérée lorsqu'elle est utilisée sur un objet Python. Ici, nous l'avons remplacé de sorte que lorsqu'il ==est utilisé sur des objets de type, Fooil renvoie toujours true. Il n'y a pas de méthode équivalente pour l' isopérateur et le comportement de isne peut donc pas être modifié de la même manière.
Brendan
Est-ce parce que la définition de la classe foo n'a pas de constructeur, c'est-à-dire la fonction init ?
étudier
49

Vous voudrez peut-être lire l' identité et l'équivalence de cet objet .

L'instruction «est» est utilisée pour l'identité de l'objet, elle vérifie si les objets se réfèrent à la même instance (même adresse en mémoire).

Et l'instruction '==' fait référence à l'égalité (même valeur).

borrego
la source
Hmmm, je pense que votre lien a changé, sauf si vous étiez intéressé par la façon d'appeler des fonctions externes à partir de python
Pat
Je viens d'essayer a=1;b=1;print(a is b) # True. Une idée pourquoi a is bse révéler vrai même s'ils semblent être 2 objets différents (adresse différente en mémoire)?
Johnny Chiu
24

Un mot d'avertissement:

if foo:
  # do something

N'est pas exactement le même que:

if x is not None:
  # do something

Le premier est un test de valeur booléenne et peut être évalué à faux dans différents contextes. Il y a un certain nombre de choses qui représentent faux dans une valeur booléenne teste par exemple des conteneurs vides, des valeurs booléennes. Aucun n'évalue également faux dans cette situation, mais d'autres choses aussi.

Tendayi Mawushe
la source
12

(ob1 is ob2) égal à (id(ob1) == id(ob2))

Mykola Kharechko
la source
6
... mais (ob est ob2) est beaucoup plus rapide. Timeit indique que "(a is b)" est de 0,0365 usec par boucle et "(id (a) == id (b))" est de 0,153 usec par boucle. 4.2x plus rapide!
AKX
4
la isversion n'a besoin d'aucun appel de fonction et d'aucune recherche d'attribut python-interpreter; l'interprète peut répondre immédiatement si ob1 est, en fait, ob2.
u0b34a0f6ae
17
Non. {} is {}est faux et id({}) == id({})peut être (et est en CPython) vrai. Voir stackoverflow.com/questions/3877230
Piotr Dobrogost
12

La raison en foo is Noneest que la méthode préférée est que vous pourriez manipuler un objet qui définit le sien __eq__, et qui définit l'objet comme égal à Aucun. Donc, utilisez toujours foo is Nonesi vous avez besoin de voir si c'est infact None.

truppo
la source
8

Il n'y a pas de différence car les objets identiques seront bien sûr égaux. Cependant, PEP 8 indique clairement que vous devez utiliser is:

Les comparaisons avec des singletons comme None doivent toujours être faites avec is ou is, jamais avec les opérateurs d'égalité.

Thijs van Dien
la source
7

istests d'identité, pas d' égalité. Pour votre déclaration foo is none, Python compare simplement l'adresse mémoire des objets. Cela signifie que vous posez la question "Ai-je deux noms pour le même objet?"

==d'autre part, teste l'égalité telle que déterminée par la __eq__()méthode. Peu importe l'identité.

In [102]: x, y, z = 2, 2, 2.0

In [103]: id(x), id(y), id(z)
Out[103]: (38641984, 38641984, 48420880)

In [104]: x is y
Out[104]: True

In [105]: x == y
Out[105]: True

In [106]: x is z
Out[106]: False

In [107]: x == z
Out[107]: True

Noneest un opérateur singleton. C'est None is Nonetoujours vrai.

In [101]: None is None
Out[101]: True
ChillarAnand
la source
5

Pour None, il ne devrait pas y avoir de différence entre l'égalité (==) et l'identité (is). Le NoneType renvoie probablement l'identité pour l'égalité. Puisque None est la seule instance que vous pouvez faire de NoneType (je pense que c'est vrai), les deux opérations sont les mêmes. Dans le cas d'autres types, ce n'est pas toujours le cas. Par exemple:

list1 = [1, 2, 3]
list2 = [1, 2, 3]
if list1==list2: print "Equal"
if list1 is list2: print "Same"

Cela afficherait "Equal" car les listes ont une opération de comparaison qui n'est pas le retour d'identité par défaut.

Stephen Pellicer
la source
5

@ Jason :

Je recommande d'utiliser quelque chose de plus le long des lignes de

if foo:
    #foo isn't None
else:
    #foo is None

Je n'aime pas utiliser "if foo:" à moins que foo ne représente vraiment une valeur booléenne (c'est-à-dire 0 ou 1). Si foo est une chaîne ou un objet ou quelque chose d'autre, "if foo:" peut fonctionner, mais cela ressemble à un raccourci paresseux pour moi. Si vous vérifiez si x est Aucun, dites "si x est Aucun:".

Graeme Perrow
la source
La vérification des chaînes / listes vides avec "if var" est la méthode préférée. La conversion booléenne est bien définie et c'est moins de code qui fonctionne même mieux. Aucune raison de faire "if len (mylist) == 0" par exemple.
truppo
Faux. Supposons que foo = "". Ensuite if fooretournera false et le commentaire #foo is Noneest erroné.
blokeley
Note aux downvoters - ma réponse cite une réponse qui a depuis été supprimée et n'est pas d'accord avec elle. Si vous n'aimez pas le code dans ma réponse, vous devez voter . :-)
Graeme Perrow
2

Quelques détails supplémentaires:

  1. La isclause vérifie en fait si les deux objects sont au même emplacement mémoire ou non. c'est-à-dire s'ils pointent tous deux vers le même emplacement mémoire et ont le même id.

  2. En conséquence de 1, isassure si oui ou non les deux objects lexicalement représentés ont des attributs identiques (attributs-d'attributs ...) ou non

  3. Instanciation des types primitifs comme bool, int, string(à quelques exceptions près), NoneTypeayant une même valeur sera toujours dans le même emplacement mémoire.

Par exemple

>>> int(1) is int(1)
True
>>> str("abcd") is str("abcd")
True
>>> bool(1) is bool(2)
True
>>> bool(0) is bool(0)
True
>>> bool(0)
False
>>> bool(1)
True

Et comme NoneTypeil ne peut y avoir qu'une seule instance de lui-même dans la table de "recherche" du python, le premier et le second sont plus un style de programmation du développeur qui a écrit le code (peut-être pour la cohérence) plutôt que d'avoir une raison logique subtile de choisissez l'un plutôt que l'autre.

Doigts saignants
la source
2
Tout le monde lisant ceci: NE PAS utiliser some_string is "bar"pour comparer les chaînes JAMAIS. Il n'y a PAS UNE SEULE RAISON ACCEPTABLE pour le faire et cela CASSERA quand vous ne vous y attendez pas. Le fait que cela fonctionne souvent est simplement parce que CPython sait qu'il serait stupide de créer deux objets immuables qui ont le même contenu. Mais cela peut néanmoins arriver.
ThiefMaster
@ThiefMaster la réponse a-t-elle tendance à être mal interprétée? Cependant, en le relisant, je n'ai pas pu le trouver (avec la mention de "quelques exceptions"). Votre déclaration ne vaut que pour les chaînes et non int, non?
Bleeding Fingers
Pas vraiment, mais comme vous avez cet exemple dans votre réponse, j'ai pensé que ce serait une bonne idée d'avertir les utilisateurs que c'est une mauvaise idée de l'utiliser réellement. Peut-être ajouter quelque chose comme "# cpython spécifique / non garanti" derrière cette ligne ...
ThiefMaster
1

La conclusion de John Machin qui Noneest un singleton est une conclusion renforcée par ce code.

>>> x = None
>>> y = None
>>> x == y
True
>>> x is y
True
>>> 

Depuis Noneest un singleton, x == Noneet x is Noneaurait le même résultat. Cependant, à mon avis esthétique,x == None c'est mieux.

ncmathsadist
la source
2
Je ne suis pas d'accord avec l'opinion à la fin de cette réponse. Lors de la comparaison avec aucun explicitement, il est généralement prévu que l'objet en question soit exactement l' Noneobjet. Par comparaison, on voit rarement None utilisé dans un autre contexte, sauf pour être similaire à Falsed'autres valeurs étant véridiques. Dans ces cas, il est plus idiomatique de faire quelque chose commeif x: pass
SingleNegationElimination
0
a is b # returns true if they a and b are true alias
a == b # returns true if they are true alias or they have values that are deemed equivalence 


a = [1,3,4]
b = a[:] #creating copy of list
a is b # if gives false
False
a == b # gives true
True
Aks
la source