[Python-Dev] decimal.py: == and != comparisons involving NaNs

Stefan Krah stefan-usenet at bytereef.org
Mon Nov 9 13:21:59 CET 2009


Antoine Pitrou <solipsis at pitrou.net> wrote:
> Stefan Krah <stefan-usenet <at> bytereef.org> writes:
> > 
> > >>> d = {0:Decimal("NaN")}
> > >>> Decimal("NaN") in d.values()
> > False
> > 
> > So, since non-decimal use cases are limited at best, the equality/inequality
> > operators might as well have the behavior of the other comparison operators,
> > which is safer for the user.
> 
> The problem is when searching for /another/ object which hashes the same as
> Decimal("NaN"). Here is a made-up situation to show you the problem:
> 
> >>> class H(object):
> ...   def __hash__(self): return hash(1)
> ...   def __eq__(self, other): raise ValueError
> ... 
> >>> h = H()
> >>> d = {h: ""}
> >>> d[1]
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
>   File "<stdin>", line 3, in __eq__
> ValueError
> >>> d[1] = 2
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
>   File "<stdin>", line 3, in __eq__
> ValueError

I see the point, but Decimal("NaN") does not hash:

>>> hash(Decimal("NaN"))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/decimal.py", line 937, in __hash__
    raise TypeError('Cannot hash a NaN value.')
TypeError: Cannot hash a NaN value.


Also, NaNs cause problems in non-decimal comparisons virtually everywhere:

>>> L = [1, 2, Decimal("NaN")]
>>> L.sort()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/decimal.py", line 877, in __lt__
    ans = self._compare_check_nans(other, context)
  File "/usr/lib/python2.7/decimal.py", line 782, in _compare_check_nans
    self)
  File "/usr/lib/python2.7/decimal.py", line 3755, in _raise_error
    raise error(explanation)
decimal.InvalidOperation: comparison involving NaN
>>> 


I think problems like these would best be avoided by having a separate
__totalorder__ or __lexorder__ method instead of using __eq__, __lt__,
etc., but this is of course outside the scope of this discussion (and
I have no idea how difficult it would be to implement that).



Stefan Krah




More information about the Python-Dev mailing list