Почему сравнение строк с использованием '==' или 'is' иногда дает другой результат?
У меня есть программа Python, где две переменные установлены на значение 'public'
. В условном выражении у меня есть сравнение var1 is var2
, которое терпит неудачу, но если я изменю его на var1 == var2
, он вернет True
.
Теперь, если я открою свой интерпретатор Python и сделаю то же сравнение "есть", он преуспеет.
>>> s1 = 'public'
>>> s2 = 'public'
>>> s2 is s1
True
Что мне здесь не хватает?
Ответы
Ответ 1
is
- тестирование идентичности, ==
- проверка равенства. то, что происходит в вашем коде, будет эмулироваться в интерпретаторе следующим образом:
>>> a = 'pub'
>>> b = ''.join(['p', 'u', 'b'])
>>> a == b
True
>>> a is b
False
так что неудивительно, что они не то же самое, верно?
Другими словами: is
- это id(a) == id(b)
Ответ 2
Другие ответы здесь верны: is
используется для сравнения идентичности, а ==
используется для сравнения равенств. Так как вы заботитесь о равенстве (две строки должны содержать одни и те же символы), в этом случае оператор is
просто ошибочен, и вместо этого вы должны использовать ==
.
Причина is
работает интерактивно в том, что (большинство) строковых литералов интернировано по умолчанию. Материал из Википедии:
Интернированные строки ускоряют строку сравнения, которые иногда являются узкое место в приложениях (например, компиляторы и динамические время программирования языка программирования), что в значительной степени полагаются на хеш-таблицы с строковые ключи. Без интернирования, проверяя, что две разные строки равны, включает в себя изучение каждого характер обеих строк. Это медленно по нескольким причинам: это по существу, O (n) в длине строки; обычно требуется чтение из нескольких областей памяти, которые занимать время; и чтение заполняет процессорный кеш, то есть меньше кэш доступен для других нужд. С интернированные строки, простой объект теста идентичности достаточно после оригинальная стажерская работа; это обычно реализуемый как указатель тест равенства, обычно один машинная инструкция без памяти ссылка вообще.
Итак, когда у вас есть две строковые литералы (слова, которые буквально введены в исходный код вашей программы, окруженные кавычками) в вашей программе, которые имеют одинаковое значение, компилятор Python будет автоматически ставить строки, делая их как сохраненными в том же месте памяти. (Обратите внимание, что это не всегда происходит, и правила для того, когда это происходит, довольно запутаны, поэтому, пожалуйста, не полагайтесь на это поведение в производственном коде!)
Так как в вашем интерактивном сеансе обе строки фактически хранятся в одном месте памяти, они имеют одинаковый идентификатор, поэтому оператор is
работает так, как ожидалось. Но если вы построите строку каким-либо другим методом (даже если эта строка содержит точно такие же символы), то строка может быть одинаковой, но это не одна и та же строка, то есть она имеет различную идентификацию, поскольку она хранятся в другом месте в памяти.
Ответ 3
Ключевое слово is
- это тест для идентификации объекта, а ==
- сравнение значений.
Если вы используете is
, результат будет истинным тогда и только тогда, когда объект является тем же самым объектом. Тем не менее, ==
будет истинным в любое время, когда значения объекта будут одинаковыми.
Ответ 4
Наконец, вы можете использовать функцию intern, чтобы убедиться, что вы получаете ссылку на одну и ту же строку:
>>> a = intern('a')
>>> a2 = intern('a')
>>> a is a2
True
Как указывалось выше, вы, вероятно, не должны делать это, чтобы определить равенство по строкам. Но это может быть полезно узнать, есть ли у вас какое-то странное требование использовать is
.
Обратите внимание, что функция intern перешла из встроенной функции в модуль sys
для Python 3.
Ответ 5
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
Они одинакового возраста, но они не похожи на человека. Строка может быть эквивалентна другой, но это не тот же объект.
Ответ 6
Это побочная заметка, но в идиоматическом питоне вы часто увидите такие вещи, как:
if x is None:
# some clauses
Это безопасно, потому что гарантированно будет один экземпляр объекта Null (т.е. None).
Ответ 7
Если вы не знаете, что делаете, используйте '=='.
Если у вас есть немного больше знаний об этом, вы можете использовать "is" для известных объектов, таких как "Нет".
В противном случае вы будете удивлены, почему все не работает и почему это происходит:
>>> a = 1
>>> b = 1
>>> b is a
True
>>> a = 6000
>>> b = 6000
>>> b is a
False
Я даже не уверен, что некоторые вещи гарантированно останутся неизменными между различными версиями/реализациями python.
Ответ 8
Из моего ограниченного опыта работы с python is
используется для сравнения двух объектов, чтобы увидеть, являются ли они тем же объектом, что и два разных объекта с одинаковым значением. ==
используется для определения идентичности значений.
Вот хороший пример:
>>> s1 = u'public'
>>> s2 = 'public'
>>> s1 is s2
False
>>> s1 == s2
True
s1
является строкой unicode, а s2
является обычной строкой. Они не одного типа, но имеют одинаковое значение.
Ответ 9
Я думаю, что это связано с тем фактом, что, когда сравнение 'is' оценивается как false, используются два разных объекта. Если он оценивает значение true, это означает, что внутри он использует один и тот же точный объект, а не создает новый, возможно, потому, что вы создали их за долю в 2 или около того секунд и потому, что между ним не было большого промежутка времени использует тот же объект.
Вот почему вы должны использовать оператор равенства ==
, а не is
, чтобы сравнить значение строкового объекта.
>>> s = 'one'
>>> s2 = 'two'
>>> s is s2
False
>>> s2 = s2.replace('two', 'one')
>>> s2
'one'
>>> s2 is s
False
>>>
В этом примере я сделал s2, который был другим строковым объектом, ранее равным "одному", но это не тот же объект, что и s
, потому что интерпретатор не использовал тот же объект, который я изначально не назначал это "один", если бы у меня было это, это сделало бы их одним и тем же объектом.
Ответ 10
Я считаю, что это известно как "интернированные" строки. Python делает это, так же как и Java, а также C и С++ при компиляции в оптимизированных режимах.
Если вы используете две идентичные строки, вместо того, чтобы тратить память на создание двух строковых объектов, все интернированные строки с одним и тем же содержимым указывают на одну и ту же память.
В результате оператор Python "is" возвращает True, потому что две строки с одним и тем же содержимым указывают на один и тот же строковый объект. Это также произойдет в Java и в C.
Это полезно только для экономии памяти. Вы не можете полагаться на него, чтобы проверить соответствие строк, поскольку различные интерпретаторы, компиляторы и JIT-механизмы не всегда могут это сделать.
Ответ 11
Я отвечаю на вопрос, даже если вопрос старен, потому что никакие ответы выше не цитируют ссылку на язык
Фактически оператор-оператор проверяет идентификаторы и == для проверки равенства,
Из справочника по языку:
Типы затрагивают почти все аспекты поведения объекта. Даже значение значимости объекта в некотором смысле влияет: для неизменяемых типов операции , которые вычисляют новые значения, могут фактически возвращать ссылку на любой существующий объект с тем же типом и значением, тогда как для изменяемых объектов это недопустимо. Например, после a = 1; b = 1, a и b могут или не могут ссылаться на один и тот же объект со значением один, в зависимости от реализации, но после c = []; d = [], c и d гарантированно относятся к двум различным уникальным, вновь созданным пустым спискам. (Обратите внимание, что c = d = [] присваивает один и тот же объект как c, так и d.)
поэтому из вышеприведенного утверждения мы можем сделать вывод о том, что строки, которые являются неизменяемым, могут быть сбой при проверке с помощью "is" и могут проверяться успешно, когда отмечен с помощью "is"
То же самое относится к int, кортежу, которые также являются неизменяемыми типами
Ответ 12
Эквивалентность значения оператора ==
. Оператор is
проверяет идентичность объекта, Python проверяет, являются ли оба из них одним и тем же объектом (т.е. Живут по одному и тому же адресу в памяти).
>>> a = 'banana'
>>> b = 'banana'
>>> a is b
True
В этом примере Python создал только один строковый объект, и на него ссылаются как a
, так и b
. Причина в том, что Python внутренне кэширует и использует несколько строк в качестве оптимизации, на самом деле в памяти есть только строка "банан", разделяемая a и b; Чтобы вызвать нормальное поведение, вам нужно использовать более длинные строки:
>>> a = 'a longer banana'
>>> b = 'a longer banana'
>>> a == b, a is b
(True, False)
При создании двух списков вы получаете два объекта:
>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> a is b
False
В этом случае мы бы сказали, что два списка эквивалентны, потому что они имеют одинаковые элементы, но не идентичны, потому что они не являются одним и тем же объектом. Если два объекта идентичны, они также эквивалентны, но если они эквивалентны, они не обязательно идентичны.
Если a
относится к объекту и вы назначаете b = a
, то обе переменные относятся к одному и тому же объекту:
>>> a = [1, 2, 3]
>>> b = a
>>> b is a
True
Ответ 13
is
сравнивает ячейку памяти. Он используется для сравнения на уровне объектов.
==
будет сравнивать переменные в программе. Используется для проверки на уровне значения.
is
проверяет эквивалентность на уровне адресов
==
проверяет эквивалентность на уровне значений
Ответ 14
is
- тестирование идентичности, ==
- проверка равенства (см. Документация на Python).
В большинстве случаев, если a is b
, то a == b
. Но есть исключения, например:
>>> nan = float('nan')
>>> nan is nan
True
>>> nan == nan
False
Таким образом, вы можете использовать только is
для тестов идентичности, никогда не анализируя тесты равенства.
Ответ 15
Вместо этого попробуйте использовать
s1='public'
s2='public'
sorted(s1) == sorted(s2)
Выше код даст результат как TRUE
s1='public'
s2='publci'
sorted(s1) == sorted(s2)
Выше код даст результат как TRUE
s1='public'
s2='publca'
sorted(s1) == sorted(s2)
Выше код даст результат как FALSE