Почему сравнение строк с использованием '==' или 'is' иногда дает другой результат? - PullRequest
1030 голосов
/ 01 октября 2009

У меня есть программа на Python, в которой двум переменным присвоено значение 'public'. В условном выражении у меня есть сравнение var1 is var2, которое не удается, но если я изменяю его на var1 == var2, оно возвращает True.

Теперь, если я открою свой интерпретатор Python и выполнил то же самое сравнение "is", это будет успешно.

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

Что мне здесь не хватает?

Ответы [ 14 ]

1402 голосов
/ 01 октября 2009

is - проверка личности, == - проверка на равенство. то, что происходит в вашем коде, будет эмулироваться в интерпретаторе следующим образом:

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

итак, не удивительно, что они не одинаковы, верно?

Другими словами: is это id(a) == id(b)

513 голосов
/ 01 октября 2009

Другие ответы здесь верны: is используется для идентичности сравнения, а == используется для равенства сравнения. Поскольку вас волнует равенство (две строки должны содержать одинаковые символы), в этом случае оператор is просто неверен, и вы должны использовать вместо него ==.

Причина, по которой is работает в интерактивном режиме, заключается в том, что (большинство) строковых литералов по умолчанию интернированы . Из Википедии:

Стажированные строки ускоряют строку сравнения, которые иногда узкое место производительности в приложениях (такие как компиляторы и динамические время выполнения языка программирования), что полагаться на хэш-таблицы с строковые ключи. Без стажировки, проверяя, что две разные строки равны включает в себя изучение каждого характер обеих строк. Это медленно по нескольким причинам: это по сути O (n) в длине строки; обычно требуется чтение из нескольких областей памяти, которые занимать время; и читает заполняет кеш процессора, значит там меньше кеш доступен для других нужд. С интернированные строки, простой объект Тест идентичности достаточно после оригинальная интерновская операция; это обычно реализуется как указатель тест на равенство, как правило, только один машинная инструкция без памяти ссылка вообще.

Таким образом, когда в вашей программе есть два строковых литерала (слова, которые буквально набираются в исходный код вашей программы, заключены в кавычки), которые имеют одинаковое значение, компилятор Python автоматически объединяет строки, делая их оба сохраненными. в том же месте памяти. (Обратите внимание, что это не всегда происходит, и правила, когда это происходит, довольно запутанны, поэтому, пожалуйста, не полагайтесь на это поведение в рабочем коде!)

Поскольку в вашем интерактивном сеансе обе строки фактически хранятся в одной и той же ячейке памяти, они имеют одинаковую идентичность , поэтому оператор is работает, как и ожидалось. Но если вы строите строку другим методом (даже если эта строка содержит точно тех же символов), тогда строка может быть равна , но это не то же самое строка - то есть она имеет другую идентичность , потому что она хранится в другом месте в памяти.

100 голосов
/ 01 октября 2009

Ключевое слово is - это тест на идентичность объекта, а == - сравнение значений.

Если вы используете is, результат будет истинным, если и только если объект является тем же объектом. Однако == будет истинным в любое время, когда значения объекта совпадают.

54 голосов
/ 01 октября 2009

Последнее, что следует отметить, вы можете использовать функцию intern, чтобы убедиться, что вы получаете ссылку на ту же строку:

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

Как указывалось выше, вам, вероятно, не следует определять равенство строк. Но это может быть полезно знать, если у вас есть какое-то странное требование использовать is.

Обратите внимание, что функция intern перешла из встроенной функции в модуль sys для Python 3.

38 голосов
/ 29 апреля 2013

is - проверка личности, == - проверка на равенство. Это означает, что is - это способ проверить, являются ли две вещи одинаковыми вещами или просто эквивалентными

Скажем, у вас есть простой person объект. Если его зовут Джек и ему 23 года, он эквивалентен другому 23-летнему Джеку, но это не тот человек.

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

Они одного возраста, но это не один и тот же человек. Строка может быть эквивалентна другой, но это не тот же объект.

34 голосов
/ 01 октября 2009

Это примечание, но в идиоматическом питоне вы часто увидите такие вещи, как:

if x is None: 
    # some clauses

Это безопасно, потому что гарантированно будет один экземпляр Null Object (т. Е. None) .

26 голосов
/ 01 октября 2009

Если вы не уверены, что делаете, используйте '=='. Если у вас есть немного больше знаний об этом, вы можете использовать «is» для известных объектов, таких как «None».

В противном случае вы будете удивляться, почему что-то не работает и почему это происходит:

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

Я даже не уверен, гарантируется ли, что некоторые вещи остаются неизменными между различными версиями / реализациями Python.

19 голосов
/ 01 октября 2009

Из моего ограниченного опыта работы с Python, is используется для сравнения двух объектов, чтобы увидеть, являются ли они одним и тем же объектом, в отличие от двух разных объектов с одинаковым значением. == используется для определения идентичности значений.

Вот хороший пример:

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

s1 - это строка в юникоде, а s2 - обычная строка. Они не одного типа, но имеют одинаковое значение.

16 голосов
/ 01 октября 2009

Я думаю, что это связано с тем фактом, что, когда сравнение 'is' оценивается как ложное, используются два различных объекта. Если он оценивается как true, это означает, что внутри он использует один и тот же точный объект, а не создает новый, возможно, потому, что вы создали их в течение доли или около того секунд, и потому что между его оптимизацией и большим промежутком времени нет. использует тот же объект.

Вот почему вы должны использовать оператор равенства ==, а не is, для сравнения значения строкового объекта.

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

В этом примере я сделал s2, который был другим строковым объектом, ранее равным 'one', но это не тот же объект, что и s, потому что интерпретатор не использовал тот же объект, который я изначально не назначал это «один», если бы у меня было бы, сделал бы их один и тот же объект.

12 голосов
/ 01 октября 2009

Я считаю, что это известно как "интернированные" строки. Это делает и Python, и Java, и C и C ++ при компиляции в оптимизированных режимах.

Если вы используете две одинаковые строки вместо того, чтобы тратить память на создание двух строковых объектов, все интернированные строки с одинаковым содержимым указывают на одну и ту же память.

В результате оператор Python "is" возвращает True, поскольку две строки с одинаковым содержимым указывают на один и тот же строковый объект. Это также произойдет в Java и C.

Это полезно только для экономии памяти. Вы не можете положиться на него для проверки на равенство строк, потому что различные интерпретаторы и компиляторы и механизмы JIT не всегда могут это сделать.

...