Вопрос-Ответ

Why does comparing strings using either '==' or 'is' sometimes produce a different result?

Почему сравнение строк с использованием '==' или 'is' иногда дает другой результат?

Двум строковым переменным присваивается одно и то же значение. s1 == s2 всегда возвращает True, но s1 is s2 иногда возвращает False.

Если я открою свой интерпретатор Python и проделаю то же самое is сравнение, оно завершится успешно:

>>> s1 = 'text'
>>> s2 = 'text'
>>> s1 is s2
True

Почему это?

Переведено автоматически
Ответ 1

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

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

Итак, неудивительно, что они не совпадают, не так ли?

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

Ответ 2

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

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


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


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

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

Ответ 3

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

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

Ответ 4

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

>>> from sys import intern
>>> a = intern('a')
>>> a2 = intern('a')
>>> a is a2
True

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

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

python string