Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Python 3 raising an error where Python 2 did not

3,381 views
Skip to first unread message

d...@forestfield.co.uk

unread,
Aug 26, 2016, 4:51:35 AM8/26/16
to
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.

David Hughes
Forestfield Software

Chris Angelico

unread,
Aug 26, 2016, 5:08:10 AM8/26/16
to
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@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@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

Peter Otten

unread,
Aug 26, 2016, 5:38:08 AM8/26/16
to
Because allowing comparisons between object of arbitrary type does more harm
than benefit?

[Python 2]
>>> sorted([1, "2", 3])
[1, 3, '2']

In the rare case where you actually want to compare different types you can
make that explicit:

[Python 3]
>>> sorted([1, "2", 3], key=int)
[1, '2', 3]
>>> sorted([1, "2", 3], key=lambda x: (type(x).__name__, x))
[1, 3, '2']
>>> sorted([1, "2", 3], key=lambda x: (not isinstance(x, str), x))
['2', 1, 3]
>>> from itertools import product
>>> for x, y in product([None, 1], repeat=2):
... print(x, ">", y, "-->", (x is not None, x) > (y is not None, y))
...
None > None --> False
None > 1 --> False
1 > None --> True
1 > 1 --> False


d...@forestfield.co.uk

unread,
Aug 26, 2016, 10:06:56 AM8/26/16
to
Thanks for the replies. My example seems to be from the fairly harmless end of a wedge of behaviours that are being handled much more sensibly in Python 3.


Terry Reedy

unread,
Aug 26, 2016, 3:52:52 PM8/26/16
to
On 8/26/2016 4:50 AM, d...@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

The response 'False' is not a defined part of the language and no
program should depend on it. An earlier version of CPython and another
implementation of Python 1 or 2 might have said 1 or True. Then your
'first divisor > 1' would be None. Not good.

--
Terry Jan Reedy

0 new messages