There's been some work going on recently on Py2 vs Py3 object comparisons. If you want all the background, see gh-6265 and follow the links there.

There is a half baked PR in the works, gh-6269, that tries to unify behavior and fix some bugs along the way, by replacing all 2.x uses of PyObject_Compare with several calls to PyObject_RichCompareBool, which is available on 2.6, the oldest Python version we support.

The poster child for this example is computing np.sign on an object array that has an np.nan entry. 2.x will just make up an answer for us:

>>> cmp(np.nan, 0)
-1

even though none of the relevant compares succeeds:

>>> np.nan < 0
False
>>> np.nan > 0
False
>>> np.nan == 0
False

The current 3.x is buggy, so the fact that it produces the same made up result as in 2.x is accidental:

>>> np.sign(np.array([np.nan], 'O'))
array([-1], dtype=object)

Looking at the code, it seems that the original intention was for the answer to be `0`, which is equally made up but perhaps makes a little more sense.

There are three ways of fixing this that I see:
  1. Arbitrarily choose a value to set the return to. This is equivalent to choosing a default return for `cmp` for comparisons. This preserves behavior, but feels wrong.
  2. Similarly to how np.sign of a floating point array with nans returns nan for those values, return e,g, None for these cases. This is my preferred option.
  3. Raise an error, along the lines of the TypeError: unorderable types that 3.x produces for some comparisons.
Thoughts anyone?

Jaime
-- 
(\__/)
( O.o)
( > <) Este es Conejo. Copia a Conejo en tu firma y ayúdale en sus planes de dominación mundial.