[Python-Dev] python 3 niggle: None < 1 raises TypeError
Terry Reedy
tjreedy at udel.edu
Mon Feb 17 16:29:14 CET 2014
On 2/17/2014 7:25 AM, M.-A. Lemburg wrote:
> On 17.02.2014 13:12, Nick Coghlan wrote:
>> On 17 Feb 2014 21:15, "M.-A. Lemburg" <mal at egenix.com> wrote:
>>>
>>> On 15.02.2014 07:03, Stephen J. Turnbull wrote:
>>>> M.-A. Lemburg writes:
>>>>
>>>> > IMO, it was a mistake to have None return a TypeError in
>>>> > comparisons, since it makes many typical data operations
>>>> > fail, e.g.
>>>>
>>>> I don't understand this statement. The theory is that they *should*
>>>> fail.
>>>>
>>>> The example of sort is a good one. Sometimes you want missing values
>>>> to be collected at the beginning of a list, sometimes at the end.
>>>> Sometimes you want them treated as top elements, sometimes as bottom.
>>>> And sometimes it is a real error for missing values to be present.
>>>> Not to mention that sometimes the programmer simply hasn't thought
>>>> about the appropriate policy. I don't think Python should silently
>>>> impose a policy in that case, especially given that the programmer may
>>>> have experience with any of the above treatments in other contexts.
>>>
>>> None is special in Python and has always (and intentionally) sorted
>>> before any other object. In data processing and elsewhere in Python
>>> programming, it's used to signal: no value available.
>>
>> This is the first I've ever heard of that sorting behaviour being an
>> intentional feature, rather than just an artefact of Python 2 allowing
>> arbitrarily ordered comparisons between different types. Can you point me
>> to the relevant entry in the Python 2 language reference?
>
> This is not documented anywhere in the language spec, AFAIK.
http://docs.python.org/2/reference/expressions.html#not-in
"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."
http://docs.python.org/2/library/stdtypes.html#comparisons
"Objects of different types, except different numeric types and
different string types, never compare equal; such objects are ordered
consistently but arbitrarily"
It goes on to note the exception for complex numbers, but none for None.
It continues
"CPython implementation detail: Objects of different types except
numbers are ordered by their type names;"
Again, there is no exception noted for None, although, since the type
name of None is 'NoneType', its behavior does not match that doc note.
I believe that CPython implementation detail was some of the arbitrary
orderings changed in CPython between 1.3 and 2.7. I do not know whether
other implementations all mimicked CPython or not, but the reference
manual does not require that.
> It is documented in the code (Python 2.7; Object/object.c):
>
> default_3way_compare(PyObject *v, PyObject *w)
This is the 'final fallback' for comparisons, not the first thing tried.
> ...
> /* None is smaller than anything */
Reading CPython C code is not supposed to be a requirement for
programming in Python. If that comment were true, I would regard it as
only documenting a version of CPython, not the language standard. But it
is not even true in 2.7.6. But it is not even true.
>>> class Bottom(object): # get same results below without 'object'
def __lt__(self, other):
return True
# the following two results are consistent and
# contradict the claim that 'None is smaller than anything'
>>> Bottom() < None
True
>>> cmp(Bottom(), None)
-1
# the following two results are not consistent with the
# definition of cmp, so 1 of the 2 is buggy
>>> None < Bottom()
True
>>> cmp(None, Bottom())
1
It appears that 'anything' needs to be qualified as something like
'anything that does not itself handle comparison with None or is not
given a chance to do so in a particular comparison expression'.
> if (v == Py_None)
> return -1;
> if (w == Py_None)
> return 1;
> Note that it's not important whether None is smaller or greater
> than any other object. The important aspect is that it's sorting
> order is consistent and doesn't raise a TypeError when doing an
> ordered comparison with other objects.
I can agree that it might have been nice if None had been defined as a
universal bottom object, but it has not been so defined and it did not
act as such. To make it (or anything else) a true bottom object would
require a change in the way comparisons are evaluated. Comparisons with
'bottom' would have to be detected and special-cased at the beginning of
the code, not at the end as a fallback.
--
Terry Jan Reedy
More information about the Python-Dev
mailing list