Pourquoi comparer des chaînes en Python en utilisant '= = 'ou' est ' produit 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 la change en var1 == var2 elle retourne True .

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

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

Qu'est-ce que je rate ici?

910
demandé sur BuZZ-dEE 2009-10-01 19:40:14

14 réponses

is est un test d'identité, == est un test d'égalité. ce qui se passe dans votre code serait imité 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)

1250
répondu SilentGhost 2009-10-01 15:51:34

autres réponses ici sont correctes: is est utilisé pour identité comparaison, tandis que == est utilisé pour égalité comparaison. Puisque ce qui vous intéresse est l'égalité (les deux chaînes doivent contenir les mêmes caractères), dans ce cas l'opérateur is est tout simplement erroné et vous devriez utiliser == à la place.

La raison is fonctionne de manière interactive, c'est que la plupart des littéraux de chaîne sont interné par défaut. De Wikipédia:

cordes entrelacées accélèrent la corde les comparaisons, qui sont parfois un goulot d'étranglement des performances dans les applications (tels que Compilateurs et dynamique langage de programmation de logiciels d'exécution) s'appuient fortement sur les tables de hachage avec clés de chaîne. Sans interner, vérifier que deux ficelles différentes sont égaux implique d'examiner chaque caractères des deux chaînes. C'est lent pour plusieurs raisons: il est intrinsèquement O(n) dans la longueur de la chaînes de caractères; il faut généralement Lire de plusieurs régions de la mémoire, qui prendre du temps; et les lectures remplissent le cache processeur, ce qui signifie qu'il y a moins cache disponibles pour d'autres besoins. Avec les cordes internes, un objet simple le test d'identité suffit après le original stagiaire de l'opération; c'est typiquement implémenté comme un pointeur critère d'égalité, normalement une seule instruction machine sans mémoire référence à tous.

ainsi, lorsque vous avez deux chaînes de caractères (des mots qui sont 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 internalisera automatiquement les chaînes, les faisant toutes les deux stockées dans la même mémoire. (Notez que cela ne se produit pas toujours , et les règles pour quand cela se produit sont tout à fait alambiquées, alors s'il vous plaît ne vous fiez pas à ce comportement dans le code de production!)

puisque dans votre session interactive les deux chaînes sont en fait stockées dans la même mémoire, elles ont la même identité , donc l'opérateur is 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 égale , mais ce n'est pas la même chaîne -- c'est, il a un autre identité , car il est stocké dans un endroit différent dans la mémoire.

450
répondu Daniel Pryden 2018-02-02 14:28:56

le mot-clé is est un test d'identité d'objet tandis que == est une comparaison de valeur.

Si vous utilisez is , le résultat sera vrai si et seulement si l'objet est le même objet. Cependant, == sera vrai de tout temps les valeurs de l'objet sont les mêmes.

94
répondu Thomas Owens 2009-10-01 15:45:02

une dernière chose à noter, Vous pouvez utiliser la fonction intern 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 étrange à utiliser is .

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

48
répondu Jason Baker 2009-10-01 16:04:48

is est un test d'identité, == est un test d'égalité. Cela signifie que is est une façon de vérifier si deux choses sont les mêmes choses, ou tout simplement équivalent.

dites que vous avez un simple objet person . Si elle s'appelle 'Jack' et a '23' ans, C'est l'équivalent D'un autre vieux 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 la même instance de la personne. Une chaîne peut être équivalente à une autre, mais ce n'est pas le même objet.

31
répondu TankorSmash 2016-03-04 21:01:31

c'est une note secondaire, mais en Python idiomatique, vous verrez souvent des choses comme:

if x is None: 
    # some clauses

c'est sûr, parce que il est garanti d'être une instance de L'objet nul (i.e., aucun) .

28
répondu Gregg Lind 2009-10-01 19:13:54

si vous n'êtes pas sûr de ce que vous faites, utilisez le '=='. Si vous avez un peu plus de connaissances à ce sujet vous pouvez utiliser 'est' pour les objets connus comme "Aucun".

sinon vous finirez par vous demander pourquoi les choses ne fonctionnent pas et pourquoi cela arrive:

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

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

23
répondu Mattias Nilsson 2009-10-01 16:57:09

D'après 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. == sert à 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
répondu Jack M. 2009-10-01 20:04:28

je pense que cela a à voir avec le fait que, lorsque la comparaison " est " évalue à faux, deux objets distincts sont utilisés. S'il est évalué à true, cela signifie qu'en interne il utilise le même objet exact et ne pas en créer un nouveau, peut-être parce que vous les avez créés en une fraction de 2 secondes environ et parce qu'il n'y a pas un grand intervalle de temps entre les deux il est optimisé et utilise le même objet.

C'est pourquoi vous devez utiliser l'opérateur d'égalité == , pas is , pour comparer la valeur d'un objet string.

>>> 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 de chaîne différent précédemment égal à 'one' mais qui 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'ai pas initialement assigné à 'one', si je l'avais eu il aurait fait le même objet.

12
répondu meder omuraliev 2009-10-01 15:54:20

je crois que c'est ce qu'on appelle des cordes" internées". Python le fait, Java aussi, et C et c++ aussi lors de la compilation en mode optimisé.

si vous utilisez deux chaînes identiques, au lieu de gaspiller la mémoire en créant deux objets string, toutes les chaînes internes avec le même contenu pointent vers la même mémoire.

ce résultat dans le python" est " l'opérateur renvoie True parce que deux chaînes avec le même contenu pointent vers le même objet de type string. Cela se produira également en Java et en C.

c'est seulement utile pour les économies de mémoire cependant. Vous ne pouvez pas vous y fier pour tester l'égalité des chaînes, parce que les divers interpréteurs et Compilateurs et les moteurs JIT ne peuvent pas toujours le faire.

11
répondu Zan Lynx 2009-10-01 15:59:38

je réponds à la question même si la question est trop ancienne parce qu'aucune réponse ci-dessus ne cite la référence linguistique

en Fait, l'opérateur vérifie l'identité et l'opérateur == vérifie l'égalité", 151910920"

De La Langue, La Référence:

Les Types

affectent presque tous les aspects du comportement de l'objet. Même l'importance de l'identité de l'objet est affecté dans un certain sens: pour types immuables, opérations qui calculent de nouvelles valeurs peuvent en fait retourner une référence à tout objet existant avec le même type et la même valeur, tandis que pour les objets mutables ce n'est pas autorisé . Par exemple, après a = 1; b = 1, a et b peuvent ou non se référer au même objet avec la valeur one, selon l'implémentation, mais après c = []; d = [], c et d sont garantis de se référer à deux listes vides différentes, uniques, nouvellement créées. (Notez que c = d = [] assigne le même objet à C et D.)

donc à partir de la déclaration ci-dessus, nous pouvons en déduire que les chaînes qui sont un type immuable peuvent échouer lorsqu'elles sont vérifiées Avec "Est" et peuvent réussir lorsqu'elles sont vérifiées avec" est "

il en va de même pour les int, tuple qui sont aussi des types immuables

9
répondu Ram 2014-08-08 17:04:58

Le == opérateur de test de la valeur d'équivalence. L'opérateur is teste l'identité de l'objet, Python teste si les deux sont vraiment le même objet(c'est-à-dire vivent à la même adresse en mémoire).

>>> a = 'banana'
>>> b = 'banana'
>>> a is b 
True

dans cet exemple, Python n'a créé qu'un seul objet string, et les deux a et b s'y réfèrent. La raison est que Python cache intérieurement et réutilise quelques chaînes comme une optimisation, il y a vraiment juste une chaîne "banane" en mémoire, partagé par a et b; pour déclencher le comportement normal, vous devez utiliser des chaînes plus longues:

>>> a = 'a longer banana'
>>> b = 'a longer banana'
>>> a == b, a is b
(True, False)

Lorsque vous créez deux listes, vous obtenez deux objets:

>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> a is b
False

dans ce cas nous dirions que les deux listes sont équivalentes, parce qu'elles ont les mêmes éléments, mais pas identiques, parce qu'elles ne sont pas le même objet. Si deux objets sont identiques, ils sont aussi équivalents, mais s'ils sont équivalents, ils ne sont pas nécessairement identique.

si a se réfère à un objet et vous assignez b = a , alors les deux variables se réfèrent au même objet:

>>> a = [1, 2, 3]
>>> b = a
>>> b is a
True
3
répondu X. Wang 2017-10-30 09:53:14

is est une analyse d'identité, == est l'égalité de test (voir la Documentation Python ).

dans la plupart des cas, si a is b , puis a == b . Mais il y a des exceptions, par exemple:

>>> nan = float('nan')
>>> nan is nan
True
>>> nan == nan
False

ainsi, vous ne pouvez utiliser is que pour les tests d'identité, jamais les tests d'égalité.

1
répondu Ryan 2017-05-16 12:10:51

is comparera l'emplacement de la mémoire. Il est utilisé pour la comparaison au niveau de l'objet.

== comparera les variables du programme. Il est utilisé pour vérifier au niveau de la valeur.

is vérifications de l'équivalence du niveau d'adresse

== vérifie la valeur du niveau d'équivalence

0
répondu johnashu 2017-09-14 20:27:43