Понимание оператора "is"
Оператор
is
соответствует не значениям переменных, а самим экземплярам.
Что это на самом деле означает?
Я объявил две переменные с именами x
и y
, присвоив обеим переменным одинаковые значения, но это возвращает false, когда я использую is
оператор.
Мне нужно разъяснение. Вот мой код:
x = [1, 2, 3]
y = [1, 2, 3]
print(x is y) # False
Переведено автоматически
Ответ 1
Вы неправильно поняли, что тестирует is
оператор. Он проверяет, указывают ли две переменные на один и тот же объект, а не имеют ли две переменные одинаковое значение.
Из документации к is
оператору:
Операторы
is
иis not
проверяют идентичность объекта:x is y
истинно тогда и только тогда, когдаx
иy
являются одним и тем же объектом.
Вместо этого используйте оператор ==
:
print(x == y)
Это выводит True
. x
и y
- это два отдельных списка:
x[0] = 4
print(y) # prints [1, 2, 3]
print(x == y) # prints False
Если вы используете id()
функцию, вы увидите, что x
и y
имеют разные идентификаторы:
>>> id(x)
4401064560
>>> id(y)
4401098192
но если бы вы назначили y
to x
, то оба указывали бы на один и тот же объект:
>>> x = y
>>> id(x)
4401064560
>>> id(y)
4401064560
>>> x is y
True
и is
показывает, что оба являются одним и тем же объектом, он возвращает True
.
Помните, что в Python имена - это просто метки, ссылающиеся на значения; у вас может быть несколько имен, указывающих на один и тот же объект. is
сообщает, указывают ли два имени на один и тот же объект. ==
сообщает, относятся ли два имени к объектам, имеющим одинаковое значение.
Ответ 2
Другой дубликат спрашивал, почему две равные строки обычно не идентичны, на что здесь на самом деле нет ответа:
>>> x = 'a'
>>> x += 'bc'
>>> y = 'abc'
>>> x == y
True
>>> x is y
False
Итак, почему это не одна и та же строка? Особенно учитывая это:
>>> z = 'abc'
>>> w = 'abc'
>>> z is w
True
Давайте ненадолго отложим вторую часть. Как первая может быть правдой?
Интерпретатор должен был бы иметь "таблицу интернирования", таблицу, сопоставляющую строковые значения строковым объектам, поэтому каждый раз, когда вы пытаетесь создать новую строку с содержимым 'abc'
, вы получаете обратно тот же объект. ВВикипедии есть более подробное обсуждение того, как работает интернирование.
В Python есть таблица интернирования строк; вы можете вручную интернировать строки с помощью sys.intern
метода.
Фактически, Python разрешено автоматически вставлять любые неизменяемые типы, но это не требуется для этого. Разные реализации будут вставлять разные значения.
CPython (реализация, которую вы используете, если вы не знаете, какую реализацию используете) автоматически обрабатывает небольшие целые числа и некоторые специальные синглтоны, такие как False
, но не строки (или большие целые числа, или маленькие кортежи, или что-либо еще). Вы можете увидеть это довольно легко:
>>> a = 0
>>> a += 1
>>> b = 1
>>> a is b
True
>>> a = False
>>> a = not a
>>> b = True
a is b
True
>>> a = 1000
>>> a += 1
>>> b = 1001
>>> a is b
False
Хорошо, но почему были z
и w
идентичны?
Это не интерпретатор, автоматически интернирующий значения, это компилятор, сворачивающий значения.
Если одна и та же строка во время компиляции появляется дважды в одном и том же модуле (что именно это означает, определить сложно - это не то же самое, что строковый литерал, потому что r'abc'
, 'abc'
, и 'a' 'b' 'c'
— это все разные литералы, но одна и та же строка, но ее легко понять интуитивно), компилятор создаст только один экземпляр строки с двумя ссылками.
Фактически, компилятор может пойти еще дальше: 'ab' + 'c'
может быть преобразован в 'abc'
оптимизатором, и в этом случае он может быть свернут вместе с 'abc'
константой в том же модуле.
Опять же, это то, что Python разрешено, но не обязательно делать. Но в этом случае CPython всегда сворачивает небольшие строки (а также, например, небольшие кортежи). (Хотя пошаговый компилятор интерактивного интерпретатора не выполняет ту же оптимизацию, что и модульный компилятор, поэтому вы не увидите точно таких же результатов в интерактивном режиме.)
Итак, что вы должны делать по этому поводу как программист?
Ну ... ничего. У вас почти никогда не бывает причин беспокоиться о том, идентичны ли два неизменяемых значения. Если вы хотите знать, когда можно использовать a is b
вместо a == b
, вы задаете неправильный вопрос. Просто всегда используйте a == b
, за исключением двух случаев:
- Для более удобочитаемых сравнений с одноэлементными значениями , такими как
x is None
. - Для изменяемых значений, когда вам нужно знать,
x
повлияет ли изменение наy
.
Ответ 3
is
возвращает true только в том случае, если они на самом деле являются одним и тем же объектом. Если бы они были одинаковыми, изменение одного из них также отразилось бы на другом. Вот пример разницы.
>>> x = [1, 2, 3]
>>> y = [1, 2, 3]
>>> print x is y
False
>>> z = y
>>> print y is z
True
>>> print x is z
False
>>> y[0] = 5
>>> print z
[5, 2, 3]
Ответ 4
Эта аналогия, вызванная повторяющимся вопросом, может сработать:
# - Darling, I want some pudding!
# - There is some in the fridge.
pudding_to_eat = fridge_pudding
pudding_to_eat is fridge_pudding
# => True
# - Honey, what's with all the dirty dishes?
# - I wanted to eat pudding so I made some. Sorry about the mess, Darling.
# - But there was already some in the fridge.
pudding_to_eat = make_pudding(ingredients)
pudding_to_eat is fridge_pudding
# => False