NaN отлично обрабатывается, когда я проверяю его присутствие в списке или наборе. Но я не понимаю, как это сделать. [ОБНОВЛЕНИЕ: нет. он сообщается как присутствующий, если найден идентичный экземпляр NaN; если найдены только неидентичные экземпляры NaN, сообщается как отсутствует.]
-  Я думал, что присутствие в списке проверено на основе равенства, поэтому я ожидал, что NaN не будет найден, поскольку NaN!= NaN. 
-  hash (NaN) и hash (0) равны 0. Как словари и множества говорят NaN и 0 отдельно? 
-  Безопасно ли проверять присутствие NaN в произвольном контейнере с помощью оператора in? Или это зависит от реализации?
Мой вопрос касается Python 3.2.1; но если в будущих версиях есть какие-либо изменения, существующие/запланированные, я тоже хотел бы это знать.
NaN = float('nan')
print(NaN != NaN) # True
print(NaN == NaN) # False
list_ = (1, 2, NaN)
print(NaN in list_) # True; works fine but how?
set_ = {1, 2, NaN}
print(NaN in set_) # True; hash(NaN) is some fixed integer, so no surprise here
print(hash(0)) # 0
print(hash(NaN)) # 0
set_ = {1, 2, 0}
print(NaN in set_) # False; works fine, but how?
Обратите внимание, что если я добавлю экземпляр определяемого пользователем класса в list, а затем проверим на наличие сдерживания, вызывается метод экземпляра __eq__ (если он определен) - по крайней мере, в CPython. Поэтому я предположил, что сдерживание list проверяется с помощью оператора ==.
EDIT:
В ответ на романа, кажется, что __contains__ для list, tuple, set, dict ведет себя очень странно:
def __contains__(self, x):
  for element in self:
    if x is element:
      return True
    if x == element:
      return True
  return False
Я говорю "странно", потому что я не видел, чтобы это объяснялось в документации (возможно, я пропустил это), и я думаю, что это то, что не следует оставлять в качестве варианта реализации.
Конечно, один объект NaN может быть не идентичным (в смысле id) другому объекту NaN. (Это не удивительно: Python не гарантирует такую идентичность. Фактически, я никогда не видел, чтобы CPython совместно использовал экземпляр NaN, созданный в разных местах, хотя он имеет экземпляр небольшого числа или короткую строку.) Это означает, что тестирование присутствия NaN во встроенном контейнере undefined.
Это очень опасно и очень тонко. Кто-то может запустить сам код, который я показал выше, и неправильно заключить, что он безопасен для тестирования членства NaN с помощью in.
Я не думаю, что это идеальное решение этой проблемы. Один, очень безопасный подход - обеспечить, чтобы NaN никогда не добавлялись во встроенные контейнеры. (Это боль, чтобы проверить это на всем протяжении кода...)
Другая альтернатива - следить за случаями, когда in может иметь NaN с левой стороны, а в таких случаях тестировать членство NaN отдельно, используя math.isnan(). Кроме того, необходимо также избегать или переписывать другие операции (например, установить пересечение).
