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

Python: встроенные функции max/min зависят от порядка параметров

max(float('nan'), 1) оценивается с помощью nan

max(1, float('nan')) оценивается в 1

Это предполагаемое поведение?


Спасибо за ответы.

max вызывает исключение, когда итерабельность пуста. Почему Python max не вызывает исключение, если присутствует nan? Или, по крайней мере, сделать что-нибудь полезное, например return nan или игнорировать nan. Текущее поведение очень небезопасно и кажется совершенно необоснованным.

Я нашел еще более удивительное следствие этого поведения, поэтому я просто разместил связанный с ним вопрос .

4b9b3361

Ответ 1

In [19]: 1>float('nan')
Out[19]: False

In [20]: float('nan')>1
Out[20]: False

Поплавок nan не больше и не меньше целых 1. max начинается с выбора первого элемента и заменяет его только тогда, когда находит элемент, который строго больше.

In [31]: max(1,float('nan'))
Out[31]: 1

Так как nan не больше 1, возвращается 1.

In [32]: max(float('nan'),1)
Out[32]: nan

Так как 1 не больше nan, возвращается nan.


PS. Обратите внимание, что np.max обрабатывает float('nan') по-разному:

In [36]: import numpy as np
In [91]: np.max([1,float('nan')])
Out[91]: nan

In [92]: np.max([float('nan'),1])
Out[92]: nan

но если вы хотите игнорировать np.nan s, вы можете использовать np.nanmax:

In [93]: np.nanmax([1,float('nan')])
Out[93]: 1.0

In [94]: np.nanmax([float('nan'),1])
Out[94]: 1.0

Ответ 2

Я этого раньше не видел, но это имеет смысл. Обратите внимание, что nan - очень странный объект:

>>> x = float('nan')
>>> x == x
False
>>> x > 1
False
>>> x < 1
False

Я бы сказал, что поведение max в этом случае undefined - какой ответ вы ожидаете? Единственное разумное поведение - предположить, что операции антисимметричны.


Обратите внимание, что вы можете воспроизвести это поведение, сделав сломанный класс:

>>> class Broken(object):
...     __le__ = __ge__ = __eq__ = __lt__ = __gt__ = __ne__ =
...     lambda self, other: False
...
>>> x = Broken()
>>> x == x
False
>>> x < 1
False
>>> x > 1
False
>>> max(x, 1)
<__main__.Broken object at 0x024B5B50>
>>> max(1, x)
1

Ответ 3

Макс работает следующим образом:

Первый элемент устанавливается как maxval, а затем следующий сравнивается с этим значением. Сравнение всегда будет возвращать False:

>>> float('nan') < 1
False
>>> float('nan') > 1
False

Итак, если первое значение - nan, то (поскольку сравнение возвращает false), он не будет заменен на следующем шаге.

OTOH, если 1 является первым, то же самое происходит: но в этом случае, поскольку 1 был установлен, он будет максимальным.

Вы можете проверить это в коде python, просто найдите функцию min_max в Python/bltinmodule.c