Когда оператор `==` не эквивалентен оператору `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" есть "" (как и в любой другой строке).