Создание объекта x, для которого "x в [x]" возвращает False
Если мы сделаем патологический картофель следующим образом:
>>> class Potato:
... def __eq__(self, other):
... return False
... def __hash__(self):
... return random.randint(1, 10000)
...
>>> p = Potato()
>>> p == p
False
Мы можем разбить наборы и dicts таким образом (обратите внимание: это то же самое, даже если __eq__
возвращает True
, он удаляет хэш, который их разбил):
>>> p in {p}
False
>>> p in {p: 0}
False
Также len({p: 0, p: 0}) == 2
и {p: 0}[p]
вызывает KeyError, в основном все связанные с отображением вещи выходят из окна, как и ожидалось.
Но я не ожидал, что мы не сможем разбить списки
>>> p in [p]
True
Почему? Кажется, что list.__contains__
выполняет итерацию, но сначала проверку личности перед проверкой равенства. Поскольку это означает, что идентификация означает равенство (см., Например, объект NaN), в чем причина короткого замыкания списков при сравнении идентичности?
Ответы
Ответ 1
list
, tuple
и т.д., действительно выполняет проверку идентичности перед проверкой равенства, и это поведение мотивировано этими инвариантами:
assert a in [a]
assert a in (a,)
assert [a].count(a) == 1
for a in container:
assert a in container # this should ALWAYS be true
К сожалению, dict
s, set
s, а друзья работают с помощью хэшей, поэтому, если вы общаетесь с теми, которые действительно могут эффективно их нарушить.
См. эту проблему и эту проблему для некоторой истории.
Ответ 2
В целом, нарушая предположение о том, что идентичность означает, что равенство может разбить на Python множество вещей. Верно, что NaN нарушает это предположение, и, таким образом, NaN ломает некоторые вещи на Python. Обсуждение можно найти в этой ошибке Python. В предварительно выпущенной версии Python 3.0 было исключено использование этого предположения, но разрешение ошибки заключалось в том, чтобы вернуть его (т.е. Сделать Python 3 таким же, как Python 2, в котором ярлык проверки идентификатора сделанный). документация для Python 3 правильно говорит:
Для типов контейнеров, таких как list, tuple, set, frozenset, dict или collections.deque, выражение x in y
эквивалентно any(x is e or x == e for e in y)
.
Однако, похоже, что документация для Python 2 неверна, так как она говорит:
Для типов списка и кортежа x в y истинно тогда и только тогда, когда существует индекс я такой, что x == y [i] истинно.
Вы можете поднять ошибку в документации, если хотите, хотя это довольно эзотерическая проблема, поэтому я сомневаюсь, что она будет высокой в любом списке приоритетов.