Когда, если когда-либо, использовать ключевое слово 'is' в Python?

Сегодня я узнал о ключевом слове is в Python и пробовал следующее:

>>> x=2+2
>>> y=4
>>> x is y
True

Я начал пробовать is с целыми числами, потому что знал, что ответ будет False - так что я нашел результат очень неожиданным! Чтобы дать некоторый контекст, мой фон - это С++ и С#, где существует различие между типами значений и типами объектов. В Python, как я теперь понимаю, все является ссылочным типом.

Похоже, причина, по которой x is y равна True, такая же, как объясняемая в этом вопросе, Как используется ключевое слово 'is' в Python?, который относится к использованию is со строками. То есть среда выполнения сохраняет память путем совместного использования или "интернирования" целых чисел так же, как и со строками, - это более подробно объясняется в ответах на вопрос: Python - это оператор ведет себя неожиданно с целыми числами Я нашел после моего первоначального сообщения.

Еще одна вещь, которую я нахожу удивительной, - это то, что значение, возвращаемое is, зависит от реализации. Что касается моего основного вопроса. В упомянутом вопросе о реализации строк is w.r.t было некоторое обсуждение того, когда следует использовать is, при этом несколько пользователей говорят, что они (почти) никогда не будут использовать его. Поэтому мой вопрос: когда следует использовать ключевое слово is? Каковы некоторые канонические примеры или общие правила?

Ответ 1

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

Существует канонический пример, но, к сожалению, он не очень помогает. Люди скажут вам всегда проверять значение None, используя x is None вместо x == None. Однако между этими случаями мало практических различий. (См. этот вопрос для объяснения.)

В некоторых ситуациях вы можете создать объекты, которые имеют одинаковое значение, но являются отдельными объектами. Например, вы могли бы вообразить создание фантастической игры, в которой игрок может магически создавать миньонов, чтобы сразиться с его противником. Таким образом, игрок может создать 100 одинаковых орков или что угодно. Каждый орк может быть представлен объектом, и они были бы идентичны в том, что они имеют одинаковые свойства, но все же отличаются тем, что было бы 100 отдельных объектов. Теперь, если противник пытается наложить заклинание "огненного шара" на одну из этих орков, в то время как в тот же самый ход игрок пытается бросить "защищать против огня" на орке, вы можете проверить, действительно ли цель заклинания огненного шара is цель заклинания защиты. Равенства было бы недостаточно, потому что все орки равны, но только один конкретный орк является целью каждого заклинания, и вы хотите знать, являются ли эти две цели одним и тем же объектом. Это довольно надуманный пример, но должен дать общее представление о ситуации, когда вы можете завершить работу с помощью is.

Ответ 2

"is проверяет идентификацию, а не равенство. Это означает, что Python просто сравнивает адрес памяти, в котором находится объект, в

Существует простое эмпирическое правило о том, когда использовать == или есть.

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

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

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

>>> a = [1, 2, 3]
>>> b = a
>>> b is a 
True
>>> b == a
True
>>> b = a[:]
>>> b is a
False
>>> b == a
True

Второй тест работает только потому, что Python кэширует мелкие целые объекты, что является детальностью реализации. Для больших целых чисел это не работает:

>>> 1000 is 10**3
False
>>> 1000 == 10**3
True
The same holds true for string literals:

>>> "a" is "a"
True
>>> "aa" is "a" * 2
True
>>> x = "a"
>>> "aa" is x * 2
False
>>> "aa" is intern(x*2)
True

Примечание: "Из-за автоматической сборки мусора, бесплатных списков и динамического характера дескрипторов вы можете заметить, по-видимому, необычное поведение при определенных применениях оператора is, например, связанных с сравнениями между экземплярами методы или константы".

Из-за того, как работает эталонная реализация CPython, вы получите неожиданные и непоследовательные результаты, если вы ошибочно используете это сравнение для ссылочного равенства по целым числам:

>>> a = 500
>>> b = 500
>>> a == b
True
>>> a is b
False

Это в значительной степени то, что мы ожидали: a и b имеют одинаковое значение, но представляют собой разные сущности. Но как насчет этого?

>>> c = 200
>>> d = 200
>>> c == d
True
>>> c is d
True

Это не соответствует предыдущему результату. Что здесь происходит? Оказалось, что эталонная реализация Python кэширует целые объекты в диапазоне -5,256 в качестве одноэлементных экземпляров по соображениям производительности. Вот пример, демонстрирующий это:

>>> for i in range(250, 260): a = i; print "%i: %s" % (i, a is int(str(i)));
... 
250: True
251: True
252: True
253: True
254: True
255: True
256: True
257: False
258: False
259: False

Это еще одна очевидная причина, по которой не следует использовать: поведение остается за реализацией, когда вы ошибочно используете его для равенства значений.

Ответ 3

Во-первых, причина, по которой x является y, равна True, как описано в этом вопросе. Как ключевое слово 'is' реализовано в Python?, которое относится к использованию со строками?

Это похоже. Целые числа от -5 до 256 кэшируются. Это используется для повышения производительности.

Итак, мой вопрос: когда следует использовать ключевое слово?

Вы можете использовать is, чтобы проверить, соответствуют ли две ссылки одному и тому же объекту (он проверяет объекты идентификатор). Кроме того, рекомендуется использовать is, когда вы сравниваете ссылку на объект с помощью None:

if some_object is None:
    # ...