Когда оператор `==` не эквивалентен оператору `is`? (Python)

Я заметил, что я могу использовать оператор == для сравнения всех собственных типов данных (целые числа, строки, логические значения, числа с плавающей запятой и т.д.), а также списки, кортежи, наборы и словари, содержащие собственные типы данных. В этих случаях оператор == проверяет, совпадают ли два объекта. Но в некоторых других случаях (пытаюсь сравнить экземпляры классов, которые я создал) оператор == просто проверяет, ссылаются ли две переменные на один и тот же объект (так что в этих случаях оператор == эквивалентен оператору is)

Мой вопрос: когда оператор == делает больше, чем просто сравнение тождеств?

EDIT: я использую Python 3

Ответ 1

В Python оператор == реализуется в терминах магического метода __eq__, который по умолчанию реализует его путем сравнения идентичности, Однако вы можете переопределить метод, чтобы обеспечить свою собственную концепцию равенства объектов. Обратите внимание: если вы это сделаете, вы, как правило, также переопределяете не менее __ne__ (который реализует оператор !=) и __hash__, который вычисляет хэш-код для экземпляра.

Мне было очень полезно, даже в Python, сделать реализацию __eq__ в соответствии с правилами, изложенными на языке Java, для реализаций equals, а именно:

  • Это рефлексивно: для любого ненулевого опорного значения х, x.equals(х) должна возвращать истинное.
  • Он симметричен: для любых непустых опорных значений x и y x.equals(y) должен возвращать true тогда и только тогда, когда y.equals(x) возвращает true.
  • Это транзитивно: для любых непустых опорных значений x, y и z, если x.equals(y) возвращает true, а y.equals(z) возвращает true, тогда x.equals(z) должен возвращать true.
  • Это согласовано: для любых непустых опорных значений x и y несколько вызовов x.equals(y) последовательно возвращают true или последовательно возвращают false, если информация, используемая при равных сравнениях с объектами, не изменяется.
  • Для любого ненулевого опорного значения х, x.equals(NULL) должен возвращать ложь.

последнее, вероятно, должно заменить null на None, но правила здесь не так просты в Python, как в Java.

Ответ 2

== и is всегда концептуально различны: прежние делегаты к левому объекту __eq__ [1], последний всегда проверяет личность без какого-либо делегирования. Кажется, вас смущает то, что object.__eq__ (который по-прежнему унаследован по классу, закодированному пользователем, который не переопределяет его, конечно!) Реализуется с точки зрения идентичности (в конце концов, bare object имеет абсолютно ничего, чтобы проверить кроме его идентификатор, так что еще может это сделать?! -).

[1] опуская для простоты устаревшую концепцию метода __cmp__, которая является лишь маргинальным усложнением и ничего не меняет в абзаце. -).

Ответ 3

== делает больше, чем сравнение идентификатора, когда задействованы int. Это не просто проверка того, что два int являются одним и тем же объектом; он фактически обеспечивает соответствие их значений. Рассмотрим:

>>> x=10000
>>> y=10000
>>> x==y,x is y
(True, False)
>>> del x
>>> del y
>>> x=10000
>>> y=x
>>> x==y,x is y
(True, True)

"Стандартная" реализация Python делает некоторые вещи за кулисами для небольших ints, поэтому при тестировании с небольшими значениями вы можете получить что-то другое. Сравните это с эквивалентным случаем 10000:

>>> del y
>>> del x
>>> x=1
>>> y=1
>>> x==y,x is y
(True, True)

Ответ 4

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

if myvalue is None:

не

if myvalue == None:

И никогда не использовать:

if myvalue is True:

но используйте:

if myvalue:

Этот более поздний момент для меня не так понятен, поскольку я думаю, что есть времена, чтобы отделить логическое True от других Истинных значений, таких как "Alex Martelli" , скажем, что в "Alex Martelli" нет False (абсолютно нет, это даже вызывает исключение:)), но в "Alex Martelli" есть "" (как и в любой другой строке).