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

В операторе float ( "NaN" ) и np.nan

Раньше я полагал, что оператор in в Python проверяет наличие элемента в некоторой коллекции с помощью проверки равенства ==, поэтому element in some_list примерно эквивалентен any(x == element for x in some_list). Например:

True in [1, 2, 3]
# True because True == 1

или

1 in [1., 2., 3.]
# also True because 1 == 1.

Однако хорошо известно, что NaN не равно самому себе. Поэтому я ожидал, что float("NaN") in [float("NaN")] False. И это действительно False.

Однако, если мы используем numpy.nan вместо float("NaN"), ситуация совсем иная:

import numpy as np
np.nan in [np.nan, 1, 2]
# True

Но np.nan == np.nan все еще дает False!

Как это возможно? Какая разница между np.nan и float("NaN")? Как in имеет дело с np.nan?

4b9b3361

Ответ 1

Чтобы проверить, находится ли элемент в списке, сначала тестирует Python для идентификации объекта, а затем проверяет равенство только в том случае, если объекты разные. 1

float("NaN") in [float("NaN")] False, потому что в сравнении участвуют два разных объекта NaN. Поэтому тест на идентификацию возвращает False, а затем тест равенства также возвращает False, поскольку NaN != NaN.

np.nan in [np.nan, 1, 2], однако, является Истинным, потому что тот же объект NaN участвует в сравнении. Тест на идентификацию объекта возвращает True, и поэтому Python немедленно распознает элемент как находящийся в списке.

Метод __contains__ (вызванный с помощью in) для многих других типов контейнеров Python, таких как кортежи и наборы, реализуется с использованием той же проверки.


1 По крайней мере, это верно в CPython. Идентификация объекта здесь означает, что объекты находятся по одному и тому же адресу памяти: содержит метод для списков, выполняется с помощью PyObject_RichCompareBool, который быстро сравнивает указатели объектов перед потенциально более сложным сопоставлением объектов. Другие реализации Python могут отличаться.

Ответ 2

Следует упомянуть то, что массивы numpy ведут себя так, как ожидалось:

a = np.array((np.nan,))
a[0] in a
# False

Варианты темы:

[np.nan]==[np.nan]
# True
[float('nan')]==[float('nan')]
# False
{np.nan: 0}[np.nan]
# 0
{float('nan'): 0}[float('nan')]
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# KeyError: nan

Все остальное в отличном ответе @AlexRiley.