Подтвердить что ты не робот

Создание объекта 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), в чем причина короткого замыкания списков при сравнении идентичности?

4b9b3361

Ответ 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] истинно.

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