Why does python max('a', 5) return the string value?
Asked Answered
P

2

5

Tracing back a ValueError: cannot convert float NaN to integer I found out that the line:

max('a', 5)
max(5, 'a')

will return a instead of 5.

In the above case I used the example string a but in my actual case the string is a NaN (the result of a fitting process that failed to converge).

What is the rationale behind this behaviour? Why doesn't python recognize automatically that there's a string there and that it should return the number?

Even more curious is that min() does work as expected since:

min('a', 5)
min(5, 'a')

returns 5.

Patina answered 1/2, 2015 at 1:34 Comment(2)
Related: Why None is the smallest in python?Pimiento
possible duplicate of How does Python compare string and int?Aerometeorograph
P
12

In Python 2, numeric values always sort before strings and almost all other types:

>>> sorted(['a', 5])
[5, 'a']

Numbers then, are considered smaller than strings. When using max(), that means the string is picked over a number.

That numbers are smaller is an arbitrary implementation choice. See the Comparisons documentation:

The operators <, >, ==, >=, <=, and != compare the values of two objects. The objects need not have the same type. If both are numbers, they are converted to a common type. Otherwise, objects of different types always compare unequal, and are ordered consistently but arbitrarily.

Bold emphasis mine.

Python 2 tried real hard to make heterogenous types sortable, which has caused a lot of hard to debug problems, such as programmers trying to compare integers with strings and getting unexpected results. Python 3 corrected this mistake; you'll get a TypeError instead:

>>> max(5, 'a')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: str() > int()

I've written elsewhere about the ordering rules, and even re-implemented the Python 2 rules for Python 3, if you really wanted those back.

Pimiento answered 1/2, 2015 at 1:39 Comment(7)
I'm not the downvoter, but it is not true that "numeric values always sort before other types" -- try e.g sorted(None, 23]) and you'll often see the None first even though it's not of a numeric type. It is, or rather was once Py2 is history, a really arbitrary decitionAugmentation
@AlexMartelli: None is the only exception; I didn't want to lay out the full set of rules however. I'll link to an answer where I did go into depth. The choices were once arbitrary, indeed, but since they haven't change since, now rather set in stone. :-)Pimiento
@AlexMartelli: adjusted the poor wording in the opening sentence.Pimiento
Great, but you could make both answers even better by specifying that by numbers you do not include complex ones -- Python thinks otherwise, since isinstance(1j, numbers.Number) is True!-), but it won't let you sort them anyway:-).Augmentation
@AlexMartelli: oh the perils of trying to be concise. datetime objects also don't play when sorting, not with other types anyway. There are probably some other exceptions.Pimiento
An interesting detail is that, when comparing heterogeneous types, Python 2.x compares their types as strings. The reason that numbers are less than strings is that "float", "int", and "long" are all less than "str"! That is how the "consistent but arbitrary" ordering was achieved!Bogus
@kindall: numeric types are sorted before others, full stop. The behaviour is hardcoded. float doesn't sort after array or for example. See object.c's default_3way_compare() function, note how PyNumber_Check is used? int is sorted before str not because of the sort order of their typename.Pimiento
S
2

In CPython 2.x strings are always greater than numbers, that's why you see those behaviors.

OTOH, I don't get why you think that 5 is "obviously" greater than "a"... Values of different types are comparable just for convenience (e.g. if you are building an RB tree with eterogeneous keys you want everything to be comparable), and such comparisons do define a strict weak ordering, but inter-type comparisons are not intended to be sensible in any way (how do you compare a number to a string or an object?), just coherent.

Shopper answered 1/2, 2015 at 1:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.