Как реализовано ключевое слово 'is' в Python?

... ключевое слово is, которое может использоваться для равенства в строках.

>>> s = 'str'
>>> s is 'str'
True
>>> s is 'st'
False

Я пробовал как __is__(), так и __eq__(), но они не работали.

>>> class MyString:
...   def __init__(self):
...     self.s = 'string'
...   def __is__(self, s):
...     return self.s == s
...
>>>
>>>
>>> m = MyString()
>>> m is 'ss'
False
>>> m is 'string' # <--- Expected to work
False
>>>
>>> class MyString:
...   def __init__(self):
...     self.s = 'string'
...   def __eq__(self, s):
...     return self.s == s
...
>>>
>>> m = MyString()
>>> m is 'ss'
False
>>> m is 'string' # <--- Expected to work, but again failed
False
>>>

Ответ 1

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

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

Например, ("a" * 100) is ("a" * 100) False. Обычно Python записывает каждую строку в другую ячейку памяти, интернирование обычно происходит для строковых литералов.

Ответ 2

Оператор is эквивалентен сравнению значений id(x). id в настоящее время используется для использования указателей в качестве сравнения. Поэтому вы не можете перегружать is себя, а AFAIK вы не можете перегружать id.

Итак, вы не можете. Необычно в python, но там он есть.

Ответ 3

Ключевое слово Python is проверяет идентификатор объекта. Вы не должны использовать его для проверки равенства строк. Может показаться, что он часто работает, поскольку реализации Python, как и многие языки высокого уровня, выполняют "интернирование" строк. То есть, строковые литералы и значения внутренне хранятся в хешированном списке, а те, которые идентичны, отображаются как ссылки на один и тот же объект. (Это возможно, потому что строки Python неизменяемы).

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

Ответ 4

Ключевое слово is сравнивает объекты (или, скорее, сравнивает, если две ссылки относятся к одному и тому же объекту).

Что, я думаю, почему нет механизма для предоставления вашей собственной реализации.

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

>>> a = "string"
>>> b = "string"
>>> a is b
True
>>> c = "str"+"ing"
>>> a is c
True

Вы можете с уверенностью видеть сравнение ссылок и данных в простом примере "copy":

>>> a = {"a":1}
>>> b = a
>>> c = a.copy()
>>> a is b
True
>>> a is c
False

Ответ 5

Если вы не боитесь испортить байт-код, вы можете перехватить и запланировать COMPARE_OP с помощью аргумента 8 ("is"), чтобы вызвать функцию hook для сравниваемых объектов. Посмотрите документацию модуля dis для запуска.

И не забудьте перехватить __builtin__.id() тоже, если кто-то сделает id(a) == id(b) вместо a is b.

Ответ 6

не удается сравнить строковую переменную со строковым значением и двумя строковыми переменными, когда строка начинается с '-'. Моя версия Python 2.6.6

>>> s = '-hi'
>>> s is '-hi'
False 
>>> s = '-hi'
>>> k = '-hi'
>>> s is k 
False
>>> '-hi' is '-hi'
True

Ответ 7

Вы не можете перегрузить оператор is. То, что вы хотите перегрузить, - это оператор ==. Это можно сделать, определив метод __eq__ в классе.

Ответ 8

Вы используете сравнение идентичности. == Вероятно, вы хотите. Исключением является то, когда вы хотите проверить, является ли один элемент и другой ТОЧНЫМ одним и тем же объектом и в той же позиции памяти. В ваших примерах этот элемент не является тем же, что и другой тип (my_string), чем другой (строка). Кроме того, в python нет такой вещи, как someclass. __is__ (если, конечно, вы не поместили ее там сами). Если бы было, сравнение объектов с is было бы ненадежным, просто сравните места памяти.

Когда я впервые встретил ключевое слово is, это тоже смутило меня. Я бы подумал, что это так и не изменилось. Они дали тот же результат от интерпретатора на многих объектах. Этот тип предположения фактически ТОЧНО, что есть... для. Это эквивалент питона "Эй, не ошибайтесь эти два объекта, они разные". Это, по сути, то, что [кто бы это ни было, что выпрямил меня ") сказал. Говорят много иначе, но одна точка == другая точка.

для некоторых полезных примеров и некоторого текста, чтобы помочь с иногда запутанными различиями посетите документ с почтового узла python.org, написанный "Danny Yoo"

или, если это офлайн, используйте незарегистрированный pastebin, я сделал из него тело.

если они, примерно через 20 или около того синих лун (синие луны - это реальное событие), оба опущены, я приведу примеры кода

###
>>> my_name = "danny"
>>> your_name = "ian"
>>> my_name == your_name
0                #or False
###

###
>>> my_name[1:3] == your_name[1:3]
1    #or True
###

###
>>> my_name[1:3] is your_name[1:3]
0
###

Ответ 9

'is' сравнивает идентификатор объекта, тогда как == сравнивает значения.

Пример:

a=[1,2]
b=[1,2]
#a==b returns True
#a is b returns False

p=q=[1,2]
#p==q returns True
#p is q returns True

Ответ 10

Ошибки утверждения могут легко возникать с ключевым словом when при сравнении объектов. Например, объекты a и b могут иметь одинаковое значение и совместно использовать один и тот же адрес памяти. Поэтому, делая

>>> a == b

будет оцениваться как

True

Но если

>>> a is b

оценивается как

False

вы должны, вероятно, проверить

>>> type(a)

и

>>> type(b)

Они могут быть разными и причиной сбоя.