[Python-Dev] python 3 niggle: None < 1 raises TypeError

Lennart Regebro regebro at gmail.com
Fri Feb 14 10:46:50 CET 2014


On Fri, Feb 14, 2014 at 9:04 AM, Chris Withers <chris at simplistix.co.uk> wrote:
> Hi All,
>
> Sending this to python-dev as I'm wondering if this was considered when the
> choice to have objects of different types raise a TypeError when ordered...
>
> So, the concrete I case I have is implementing stable ordering for the
> python Range objects that psycopg2 uses. These have 3 attributes that can
> either be None or, for sake of argument, a numeric value.
>
> To implement __lt__ in Python 2, I could do:
>
>     def __lt__(self, other):
>         if not isinstance(other, Range):
>             return True
>         return ((self._lower, self._upper, self._bounds) <
>                 (other._lower, other._upper, other._bounds))
>
> Because None < 1 raises a TypeError, in Python 3 I have to do:
>
>     def __lt__(self, other):
>         if not isinstance(other, Range):
>             return NotImplemented
>         for attr in '_lower', '_upper', '_bounds':
>             self_value = getattr(self, attr)
>             other_value = getattr(other, attr)
>             if self_value == other_value:
>                 pass
>             elif self_value is None:
>                 return True
>             elif other_value is None:
>                 return False
>             else:
>                 return self_value < other_value
>         return False
>
> Am I missing something? How can I get this method down to a sane size?

It was considered. It's not obvious where you want "None" to appear in
your ordering, so you will have to implement this by yourself. I can't
come up with anything obviously shorter.

Or, well, this, but it's not exactly pretty:

def __lt__(self, other):
    if not isinstance(other, Range):
        return NotImplemented
    ninf = float('-inf') # So None is lower than anything else.
    return ((self._lower if self._lower is not None else ninf,
               self._upper if self._upper is not None else ninf,
               self._bounds if self._bounds is not None else ninf) < (
               other._lower if other._lower is not None else ninf,
               other._upper if other._upper is not None else ninf,
               other._bounds if other._bounds is not None else ninf))

Or maybe:

def __lt__(self, other):
    if not isinstance(other, Range):
        return NotImplemented
    s = (self._lower, self._upper, self._bounds)
    if None is s:
        return True
    o = (other._lower, other._upper, other._bounds)
    if None in o:
        return False
    return s < o


More information about the Python-Dev mailing list