Question Pourquoi comparer des chaînes en Python en utilisant '==' ou 'est' produit-il parfois un résultat différent?


J'ai un programme Python où deux variables sont définies à la valeur 'public'. Dans une expression conditionnelle, j'ai la comparaison var1 is var2 qui échoue, mais si je le change var1 == var2 ça revient True.

Maintenant, si j'ouvre mon interpréteur Python et que je fais la même comparaison "est", ça réussit.

>>> s1 = 'public'
>>> s2 = 'public'
>>> s2 is s1
True

Qu'est-ce que j'oublie ici?


891
2017-10-01 15:40


origine


Réponses:


is est le test d'identité, == est le test d'égalité. ce qui se passe dans votre code serait émulé dans l'interpréteur comme ceci:

>>> a = 'pub'
>>> b = ''.join(['p', 'u', 'b'])
>>> a == b
True
>>> a is b
False

donc, pas étonnant qu'ils ne sont pas les mêmes, non?

En d'autres termes: is est le id(a) == id(b)


1230
2017-10-01 15:45



D'autres réponses ici sont correctes: is est utilisé pour identité comparaison, tandis que == est utilisé pour égalité Comparaison. Puisque ce qui vous importe est l'égalité (les deux chaînes doivent contenir les mêmes caractères), dans ce cas le is l'opérateur est tout simplement faux et vous devriez utiliser == au lieu.

La raison is fonctionne interactivement est que (la plupart) des littéraux de chaîne sont interné par défaut. De Wikipedia:

Les chaînes internées accélèrent la chaîne   comparaisons, qui sont parfois   goulot d'étranglement des performances dans les applications   (tels que les compilateurs et dynamiques   runtimes de langage de programmation)   compter fortement sur les tables de hachage avec   clés de chaîne. Sans internement,   vérifier que deux chaînes différentes   sont égaux consiste à examiner tous les   caractère des deux chaînes. C'est   lent pour plusieurs raisons: il est   par nature O (n) dans la longueur de la   cordes; il nécessite généralement des lectures   de plusieurs régions de la mémoire, qui   prendre du temps; et les lectures remplit le   cache du processeur, ce qui signifie qu'il y a moins   cache disponible pour d'autres besoins. Avec   chaînes internées, un objet simple   test d'identité suffit après le   opération interne originale; c'est   généralement implémenté en tant que pointeur   test d'égalité, normalement juste un seul   instruction machine sans mémoire   référence du tout.

Ainsi, lorsque vous avez deux littéraux de chaîne (mots littéralement tapés dans le code source de votre programme, entourés de guillemets) dans votre programme qui ont la même valeur, le compilateur Python va automatiquement internaliser les chaînes, les stockant toutes les deux emplacement de la mémoire. (Notez que cela ne toujours arriver, et les règles pour quand cela arrive sont assez compliquées, alors s'il vous plaît ne comptez pas sur ce comportement dans le code de production!)

Puisque dans votre session interactive les deux chaînes sont réellement stockées dans le même emplacement de mémoire, elles ont le même identité, alors le is L'opérateur fonctionne comme prévu. Mais si vous construisez une chaîne par une autre méthode (même si cette chaîne contient exactement les mêmes caractères), alors la chaîne peut être égal, mais ce n'est pas la même chaîne - Autrement dit, il a un différent identité, parce qu'il est stocké dans un endroit différent en mémoire.


440
2017-10-01 16:02



le ismot-clé est un test pour l'identité de l'objet tout en == est une comparaison de valeur.

Si tu utilises is, le résultat sera vrai si et seulement si l'objet est le même objet. cependant, == sera vrai chaque fois que les valeurs de l'objet sont les mêmes.


94
2017-10-01 15:45



Une dernière chose à noter, vous pouvez utiliser la fonction interne pour vous assurer que vous obtenez une référence à la même chaîne:

>>> a = intern('a')
>>> a2 = intern('a')
>>> a is a2
True

Comme indiqué ci-dessus, vous ne devriez probablement pas faire est de déterminer l'égalité sur les chaînes. Mais cela peut être utile de savoir si vous avez une sorte d'exigence bizarre à utiliser is.

Notez que la fonction interne a été déplacée d'une fonction intégrée à être dans le module sys pour Python 3.


48
2017-10-01 16:04



is est le test d'identité, == est le test d'égalité. Qu'est-ce que cela signifie est que is est un moyen de vérifier si deux choses sont les même choses, ou tout simplement équivalent.

Dites que vous avez un simple person objet. S'il s'appelle Jack et qu'il a 23 ans, c'est l'équivalent d'un autre Jack de 23 ans, mais ce n'est pas la même personne.

class Person(object):
   def __init__(self, name, age):
       self.name = name
       self.age = age

   def __eq__(self, other):
       return self.name == other.name and self.age == other.age

jack1 = Person('Jack', 23)
jack2 = Person('Jack', 23)

jack1 == jack2 #True
jack1 is jack2 #False

Ils ont le même âge, mais ils ne sont pas le même exemple de personne. Une chaîne peut être équivalente à une autre, mais ce n'est pas le même objet.


28
2018-04-29 00:56



C'est une note secondaire, mais dans python idiomatique, vous verrez souvent des choses comme:

if x is None: 
    # some clauses

C'est sûr, parce que il est garanti qu'il existe une instance de l'objet nul (c.-à-d., aucune).


27
2017-10-01 18:51



Si vous n'êtes pas sûr de ce que vous faites, utilisez le '=='. Si vous en savez un peu plus, vous pouvez utiliser 'is' pour des objets connus comme 'None'.

Sinon, vous finirez par vous demander pourquoi les choses ne fonctionnent pas et pourquoi cela se produit:

>>> a = 1
>>> b = 1
>>> b is a
True
>>> a = 6000
>>> b = 6000
>>> b is a
False

Je ne suis même pas sûr si certaines choses sont garanties de rester les mêmes entre les différentes versions / implémentations de python.


23
2017-10-01 16:57



De mon expérience limitée avec python, is est utilisé pour comparer deux objets pour voir s'ils sont le même objet par opposition à deux objets différents avec la même valeur. == est utilisé pour déterminer si les valeurs sont identiques.

Voici un bon exemple:

>>> s1 = u'public'
>>> s2 = 'public'
>>> s1 is s2
False
>>> s1 == s2
True

s1 est une chaîne unicode, et s2 est une chaîne normale. Ils ne sont pas du même type, mais ont la même valeur.


16
2017-10-01 15:48



Je pense que cela a à voir avec le fait que lorsque la comparaison 'est' est fausse, deux objets distincts sont utilisés. Si elle est évaluée à true, cela signifie qu'elle utilise le même objet et n'en crée pas un nouveau, peut-être parce que vous les avez créés en une fraction de 2 secondes et parce qu'il n'y a pas beaucoup de décalage entre les deux. utilise le même objet.

C'est pourquoi vous devriez utiliser l'opérateur d'égalité ==, ne pas is, pour comparer la valeur d'un objet chaîne.

>>> s = 'one'
>>> s2 = 'two'
>>> s is s2
False
>>> s2 = s2.replace('two', 'one')
>>> s2
'one'
>>> s2 is s
False
>>> 

Dans cet exemple, j'ai fait s2, qui était un objet chaîne différent précédemment égal à 'un' mais ce n'est pas le même objet que s, parce que l'interprète n'a pas utilisé le même objet que je ne l'avais initialement assigné à 'un', si je l'avais fait il aurait fait le même objet.


12
2017-10-01 15:45