Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python unorderable types: NoneType() > int() when finding max of a list

I just started with python 3 few days back. While programming, I came across strange situation

a = [
     [5, [[1, 1, None], [None, None, None], [None, None, None]]], 
     [5, [[1, None, 1], [None, None, None], [None, None, None]]]
    ]

max(a) gives me

Traceback (most recent call last): File "", line 1, in TypeError: unorderable types: NoneType() > int()

But if I try

a = [
     [5, [[1, 1, None], [None, None, None], [None, None, None]]], 
     [5.1, [[1, None, 1], [None, None, None], [None, None, None]]]
    ]

max(a) displays

[5.1, [[1, None, 1], [None, None, None], [None, None, None]]]

Any particular reason for this behaviour?

Update 1: I tried with something different

 a = [[5, [[1,2], [3,4]]],[5,[[3,4],[5,10]]],[5,[[5,6],[7,8]]]]

and max(a) is [5, [[5, 6], [7, 8]]] My doubt is why the error is not showing in this case?

like image 470
curious_coder Avatar asked Mar 04 '17 09:03

curious_coder


2 Answers

It's because max does this when it encounters None values:

max([1, None])

also gives the same error:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-14-c33cf47436bc> in <module>()
----> 1 max([1,None])

TypeError: unorderable types: NoneType() > int()

Basically max is trying to iterate over the list and find out the larger value first. But as it reaches None it can't compare any more so throws error.

with

a = [
     [5, [[1, 1, None], [None, None, None], [None, None, None]]], 
     [5.1, [[1, None, 1], [None, None, None], [None, None, None]]]
    ]

it compares 5 and 5.1 and considers list with 5.1 as bigger.

While when both first values were 5 it went to iterate the next item and ran into None which caused the error.

Update:

This example might help clarify the error message even better:

max([1,'2'])

error:

TypeError: unorderable types: str() > int()

basically it tried to compare '2' with 1 and gave TypeError: unorderable types: str() > int()

earlier we were comparing None with int() 1 and error message we got was TypeError: unorderable types: NoneType() > int()

like image 186
Vikash Singh Avatar answered Sep 23 '22 17:09

Vikash Singh


In Python 2, this None trick which compared lower to any integer was useful in some cases, when you needed a minimum value you couldn't predict (as integers don't have a fixed min/max like in C).

In Python 3 this isn't possible anymore (and most of the time it's for the best, it saves a lot of headaches when comparing strings to integers like "2" and 3 for instance.

If you really need that, I thought of a workaround.

You could define a class which is lower than any other object and use an instance of that class instead of None:

class AM:
    def __int__(self):
        return 0
    def __gt__(self,other):
        return False
    def __repr__(self):
        return "INF"   # prints out nicely

always_min = AM()

a = [
     [5, [[1, 1, always_min], [always_min, always_min, always_min]]],
     [5, [[1, always_min, 1], [always_min, always_min, always_min]]]
    ]

print(max(a))

I get:

[5, [[1, 1, INF], [INF, INF, INF]]]

which proves that tiebreak worked.

Note that this is a minimal implementation. max only uses >: defining only __gt__ is lazy, we'd need to define others __ge__, __le__, __lt__ accordingly for a general usage.

like image 31
Jean-François Fabre Avatar answered Sep 24 '22 17:09

Jean-François Fabre