2008-08-25 6 views
207

est-il une différence entre:Y at-il une différence entre "foo is None" et "foo == None"?

if foo is None: pass 

et

if foo == None: pass 

La convention que je l'ai vu dans la plupart du code Python (et le code que j'écris moi-même) est le premier, mais je suis récemment tombé à travers le code qui utilise ce dernier. None 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 être?

Répondre

239

is retourne toujours True si elle compare la même instance d'objet

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

à savoir


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

>>> f = Foo() 
>>> f == None 
True 
>>> f is None 
False 
+45

Vous pouvez vouloir ajouter que None est un singleton alors "None is None" est toujours True. –

+39

Et vous pouvez ajouter que l'opérateur 'is' ne peut pas être personnalisé (surchargé par une classe définie par l'utilisateur). – martineau

+0

Donc, dans votre cas, pourquoi le code "f == None" renvoie-t-il True? Confused ... – study

47

Vous pouvez lire ce object identity and equivalence. L'instruction 'is' est utilisée pour l'identité de l'objet, elle vérifie si les objets font référence à la même instance (même adresse en mémoire).

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

+0

Hmmm, je pense que votre lien a changé, sauf si vous étiez intéressé par * comment appeler des fonctions externes à partir de python * – Pat

4

Pour Aucun, il ne devrait pas y avoir de différence entre égalité (==) et identité (est). 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" 

Cette imprimerait « Equal » puisque les listes ont une opération de comparaison qui n'est pas le défaut de retour de l'identité.

4

@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 "si foo:" à moins foo 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 None, dites "if x is None:".

+0

La recherche de 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 le code qui fonctionne mieux. Aucune raison de faire "si len (mylist) == 0" par exemple. – truppo

+0

Incorrect. Supposons que foo = "". Alors 'si foo' retournera false et le commentaire' #foo is None' est faux. – blokeley

+0

Note aux downvoters - ma réponse cite une réponse qui a depuis été supprimée et en désaccord avec elle. Si vous n'aimez pas le code dans ma réponse, vous avez besoin de _upvote_. :-) –

23

Un mot d'avertissement:

if foo: 
    # do something 

est-pas exactement la même chose que:

if x is not None: 
    # do something 

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

12

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

+6

... mais (ob is ob2) est beaucoup plus rapide. Timeit dit "(a est b)" est 0.0365 usec par boucle et "(id (a) == id (b))" est 0,153 usec par boucle. 4.2x plus rapide! – AKX

+4

la version 'is' n'a pas besoin d'appel de fonction, et pas de recherche d'attribut python-interpreter; l'interprète peut répondre immédiatement si ob1 est, en fait, ob2. – u0b34a0f6ae

+15

Non, ce n'est pas le cas. '{} est {}' est faux et 'id ({}) == id ({})' peut être (et ** est ** dans CPython) true. Voir http://stackoverflow.com/questions/3877230 –

11

La raison foo is None est le meilleur moyen est que vous pourriez être la manipulation d'un objet qui définit son propre __eq__, et qui définit l'objet à être égal à Aucun. Donc, utilisez toujours foo is None si vous avez besoin de voir si elle est en fait None.

1

La conclusion de John Machin que None est un singleton est une conclusion soutenue par ce code.

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

Depuis None est un singleton, x == None et x is None aurait le même résultat. Cependant, dans mon opinion esthétique, x == None est le meilleur.

+2

Je ne suis pas d'accord avec l'opinion à la fin de cette réponse. Lorsque vous comparez avec aucune explicitement, il est généralement prévu que l'objet en question soit exactement l'objet 'None'. Par comparaison, on voit rarement None utilisé dans un autre contexte, sauf pour être similaire à «False» avec d'autres valeurs étant véridiques. Dans ces cas, il est plus idiomatique de faire quelque chose comme 'if x: pass' – SingleNegationElimination

1

Quelques détails:

  1. La clause is vérifie en fait, si les deux object s sont à l'emplacement même mémoire ou non. c'est-à-dire s'ils pointent tous les deux vers le même emplacement de mémoire et ont le même id.

  2. En conséquence de 1, is assure si, ou non, les deux lexicalement représenté object s ont des attributs identiques (attributs-of-attributs ...) ou non

  3. instanciation de types primitifs comme bool , int, string (avec quelques exceptions), NoneType ayant une même valeur sera toujours dans le même emplacement de mémoire.

E.g.

>>> 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 depuis NoneType ne peut avoir qu'une seule instance d'elle-même dans la table « consultation » du python donc l'ancien et ces derniers sont plus d'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 choisir l'une plutôt que l'autre.

+2

Tout le monde lit ceci: N'utilisez PAS' some_string is "bar" 'pour comparer les chaînes JAMAIS. Il n'y a PAS UNE RAISON UNIQUE ACCEPTABLE pour le faire et il se brisera quand vous ne l'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 arriver néanmoins. – ThiefMaster

+0

@ThiefMaster la réponse a-t-elle tendance à être mal interprétée? Cependant, en le relisant, je ne le trouvais pas (avec la mention de «quelques exceptions»). Votre déclaration ne vaut que pour les chaînes et non «int», non? –

+0

Pas vraiment, mais puisque 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 d'utiliser cela. Peut-être ajouter quelque chose comme "# cpython spécifique/non garanti" derrière cette ligne ... – ThiefMaster

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:

comparaisons à singletons comme Aucun devrait toujours être fait avec est ou non, jamais les opérateurs d'égalité.

4

is des tests d'identité, pas égalité. Pour votre instruction foo is none, Python compare simplement l'adresse mémoire des objets. Cela signifie que vous posez la question "Dois-je deux noms pour le même objet?" Par contre, les tests pour l'égalité sont déterminés par la méthode __eq__().

== Il ne se soucie pas de 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 

None est un opérateur singleton. Donc None is None est toujours vrai.

In [101]: None is None 
Out[101]: True 
Questions connexes