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?
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()
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With