Python 3 raising an error where Python 2 did not

Chris Angelico rosuav at gmail.com
Fri Aug 26 05:07:55 EDT 2016


On Fri, Aug 26, 2016 at 6:50 PM, dfh at forestfield.co.uk
<dfh at forestfield.co.uk> wrote:
> In a program I'm converting to Python 3 I'm examining a list of divisor values, some of which can be None, to find the first with a value greater than 1.
>
> Python 2.7.6 (default, Nov 10 2013, 19:24:18) [MSC v.1500 32 bit (Intel)] on win32
> Type "help", "copyright", "credits" or "license" for more information.
>>>> None > 1
> False
>
> Python 3.4.4 (v3.4.4:737efcadf5a6, Dec 20 2015, 20:20:57) [MSC v.1600 64 bit (AMD64)] on win32
> Type "help", "copyright", "credits" or "license" for more information.
>>>> None > 1
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> TypeError: unorderable types: NoneType() > int()
>
> I can live with that but I'm curious why it was decided that this should now raise an error.

Because it doesn't make sense to compare these things in this way. You
can compare some things (eg integers and floats), but others don't
usefully arrange themselves into any sort of order. It tends to lead
to odd situations:

rosuav at sikorsky:~$ python2
Python 2.7.12+ (default, Aug  4 2016, 20:04:34)
[GCC 6.1.1 20160724] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 10 < "15"
True
>>> "15" < 20
False
>>> "asdf" < (1,2,3)
True
>>> "asdf" > [1,2,3]
True
>>>
rosuav at sikorsky:~$ python3
Python 3.6.0a4+ (default:4b64a049f451+, Aug 19 2016, 23:41:43)
[GCC 6.1.1 20160802] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 10 < "15"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'int' and 'str'
>>>

With Py3, it's simple and obvious: comparing integers and strings is
an error. With Py2, there's the extremely odd rule that all integers
are lower than all lists are lower than all strings are lower than all
tuples - it's based on the name of the type. (Except for 'long', which
appears to sort as though it were called 'int'. I think.) The Py2
behaviour allows you to get a consistent-but-meaningless sort order
among disparate types, but it's a bug magnet, and it goes against
Python's philosophy of telling you about problems right away. Py3
fixed quite a number of those kinds of issues (eg you can't combine
byte strings and Unicode strings in Py3, yet you can in Py2), with the
result that a number of data-dependent bugs in Py2 become instant
exceptions in Py3.

The simplest way to fix your code here is to explicitly provide a
default. For instance:

divisors = [None, 1, None, 2, 7, None, 1]
greater_than_one = (div for div in divisors if (div or 0) > 1)

The (div or 0) part means that any None will be treated as zero.
(Also, zero will be treated as zero - be careful of this if you change
the default, eg to 1.) At that point, all your comparisons will
involve numbers, which have well-defined inequality comparisons.

ChrisA



More information about the Python-list mailing list