[Python-3000] None in Comparisons

2 views
Skip to first unread message

M.-A. Lemburg

unread,
Nov 11, 2008, 8:06:37 AM11/11/08
to Python 3000
Why was the special case for None being "smaller" than all other
objects in Python removed from Python 3.0 ? (see object.c in Py2.x)

There's currently a discussion on c.l.p regarding this issue (see below).

It looks like a bug in Python 3.0 to me, since None is widely used as
"n/a" object in Python.

Should I file a bug report for this ?


-------- Original Message --------
Subject: Re: Python 3.0 - is this true?
Date: Tue, 11 Nov 2008 14:02:59 +0100
From: M.-A. Lemburg <m...@egenix.com>
Organization: eGenix.com Software GmbH
To: Steven D'Aprano <ste...@REMOVE.THIS.cybersource.com.au>
CC: pytho...@python.org
References:
<64fee417-96d0-458a...@w1g2000prk.googlegroups.com>
<m28wruk...@googlemail.com>
<7edee5cc-a98e-4a72...@i20g2000prf.googlegroups.com>
<mailman.3702.1226203...@python.org>
<H7WRk.32678$b76....@newsfe21.ams2>
<pan.2008.11...@REMOVE.THIS.cybersource.com.au>

On 2008-11-11 02:10, Steven D'Aprano wrote:
> On Mon, 10 Nov 2008 12:51:51 +0000, Duncan Grisby wrote:
>
>> I have an object database written in Python. It, like Python, is
>> dynamically typed. It heavily relies on being able to sort lists where
>> some of the members are None. To some extent, it also sorts lists of
>> other mixed types. It will be very hard to migrate this aspect of it to
>> Python 3.
>
> No, it is "very hard" to sort *arbitrary* objects consistently. If it
> appears to work in Python 2.x that's because you've been lucky to never
> need to sort objects that cause it to break.

If you read Duncan's email, he isn't talking about arbitrary objects
at all. He's just referring to being able to sort lists that contain
None elements.

That's far from arbitrary and does work consistently in Python 2.x -
simply because None is a singleton which is special cased in Python:
None compares smaller to any other object in Python.

I'm not sure why this special case was dropped in Python 3.0. None
is generally used to be a place holder for a n/a-value and as
such will pop up in lists on a regular basis.

I think the special case for None should be readded to Python 3.0.

--
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source (#1, Nov 11 2008)
>>> Python/Zope Consulting and Support ... http://www.egenix.com/
>>> mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/
>>> mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/
________________________________________________________________________

:::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,MacOSX for free ! ::::


eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48
D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
Registered at Amtsgericht Duesseldorf: HRB 46611

--
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source (#1, Nov 11 2008)
>>> Python/Zope Consulting and Support ... http://www.egenix.com/
>>> mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/
>>> mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/
________________________________________________________________________

:::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,MacOSX for free ! ::::


eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48
D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
Registered at Amtsgericht Duesseldorf: HRB 46611
_______________________________________________
Python-3000 mailing list
Pytho...@python.org
http://mail.python.org/mailman/listinfo/python-3000
Unsubscribe: http://mail.python.org/mailman/options/python-3000/python-3000-garchive-63646%40googlegroups.com

Antoine Pitrou

unread,
Nov 11, 2008, 8:28:54 AM11/11/08
to pytho...@python.org

M.-A. Lemburg <mal <at> egenix.com> writes:
>
> Why was the special case for None being "smaller" than all other
> objects in Python removed from Python 3.0 ? (see object.c in Py2.x)

Because ordered comparisons (<, <=, >, >=) are much stricter in 3.0 than in 2.x.
In practice, ordered comparisons which don't have an obvious, intuitive meaning
now raise a TypeError (such as comparing a number and a string).

> It looks like a bug in Python 3.0 to me, since None is widely used as
> "n/a" object in Python.

But why should "n/a" (or "missing", or "undefined") imply "smaller than
everything else"?
I understand it might be a case of "practicality beats purity", but this is not
semantically obvious and can also let bugs slip through (the very bugs that the
stricter ordered comparison semantics in 3.0 are meant to make easier to
detect). Also there are cases where you'll want something which is *bigger* than
everything else, not smaller.

(SQL seems to do such a thing with NULL, but SQL isn't exactly a good example
for programming language design, is it?)

If it is really useful, I think i would be cleaner and more explicit to add the
Smallest and Largest constants suggested elsewhere, than reuse a very widely
used constant (None) for half of the purpose.

cheers

Antoine.

M.-A. Lemburg

unread,
Nov 11, 2008, 8:54:48 AM11/11/08
to Antoine Pitrou, pytho...@python.org
On 2008-11-11 14:28, Antoine Pitrou wrote:
> M.-A. Lemburg <mal <at> egenix.com> writes:
>> Why was the special case for None being "smaller" than all other
>> objects in Python removed from Python 3.0 ? (see object.c in Py2.x)
>
> Because ordered comparisons (<, <=, >, >=) are much stricter in 3.0 than in 2.x.
> In practice, ordered comparisons which don't have an obvious, intuitive meaning
> now raise a TypeError (such as comparing a number and a string).

That's fine. I'm just talking about the special case for None that
has existed in Python for years - and for a good reason.

>> It looks like a bug in Python 3.0 to me, since None is widely used as
>> "n/a" object in Python.
>
> But why should "n/a" (or "missing", or "undefined") imply "smaller than
> everything else"?

It's just a convention based on viewing None as "nothing" or the
empty set.

> I understand it might be a case of "practicality beats purity", but this is not
> semantically obvious and can also let bugs slip through (the very bugs that the
> stricter ordered comparison semantics in 3.0 are meant to make easier to
> detect).

Please note that I'm just talking about that one object, not all
the other cases where comparisons between apples and oranges don't
make sense :-)

> Also there are cases where you'll want something which is *bigger* than
> everything else, not smaller.

Having None compare smaller than all other objects is just a convention,
nothing more.

If there's a need for an object that compares larger than any other
object in Python, we could introduce another singleton for this, but I
don't really see the need.

> (SQL seems to do such a thing with NULL, but SQL isn't exactly a good example
> for programming language design, is it?)

NULLs are a fact in life, not only in SQL, but also in numerics and
statistics. You often don't want a complex calculation or query to
fail just because a few input values are not available.

None has been used in Python for the same purpose in these application
areas.

> If it is really useful, I think i would be cleaner and more explicit to add the
> Smallest and Largest constants suggested elsewhere, than reuse a very widely
> used constant (None) for half of the purpose.

Fair enough.

--
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source (#1, Nov 11 2008)
>>> Python/Zope Consulting and Support ... http://www.egenix.com/
>>> mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/
>>> mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/
________________________________________________________________________

:::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,MacOSX for free ! ::::


eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48
D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
Registered at Amtsgericht Duesseldorf: HRB 46611

Barry Warsaw

unread,
Nov 11, 2008, 9:07:55 AM11/11/08
to M.-A. Lemburg, pytho...@python.org, Antoine Pitrou
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Nov 11, 2008, at 8:54 AM, M.-A. Lemburg wrote:

> On 2008-11-11 14:28, Antoine Pitrou wrote:
>> M.-A. Lemburg <mal <at> egenix.com> writes:
>>> Why was the special case for None being "smaller" than all other
>>> objects in Python removed from Python 3.0 ? (see object.c in Py2.x)
>>
>> Because ordered comparisons (<, <=, >, >=) are much stricter in 3.0
>> than in 2.x.
>> In practice, ordered comparisons which don't have an obvious,
>> intuitive meaning
>> now raise a TypeError (such as comparing a number and a string).
>
> That's fine. I'm just talking about the special case for None that
> has existed in Python for years - and for a good reason.

How hard is it to implement your own "missing" object which has the
desired semantics? Why should something as fundamental as None have it?

- -Barry

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Darwin)

iQCVAwUBSRmRu3EjvBPtnXfVAQKfMgQAkV5Gm6xqRlJsPZs2SEy6kisLp//V1vlT
vGeDbF2jL+N717o2cIU21PQVWONarCStR+u98SO5EUkAAqUcKZ8gJ5x+RN376djv
fg0YsqFrgtTyFaUpfOdxc648xkbL29TK+ClX0twSG5vf+5vFs4uc4SCj7bUd6+hc
xyLqUXrybwM=
=YnKH
-----END PGP SIGNATURE-----

M.-A. Lemburg

unread,
Nov 11, 2008, 9:21:03 AM11/11/08
to Barry Warsaw, pytho...@python.org, Antoine Pitrou
On 2008-11-11 15:07, Barry Warsaw wrote:
> On Nov 11, 2008, at 8:54 AM, M.-A. Lemburg wrote:
>
>> On 2008-11-11 14:28, Antoine Pitrou wrote:
>>> M.-A. Lemburg <mal <at> egenix.com> writes:
>>>> Why was the special case for None being "smaller" than all other
>>>> objects in Python removed from Python 3.0 ? (see object.c in Py2.x)
>>>
>>> Because ordered comparisons (<, <=, >, >=) are much stricter in 3.0
>>> than in 2.x.
>>> In practice, ordered comparisons which don't have an obvious,
>>> intuitive meaning
>>> now raise a TypeError (such as comparing a number and a string).
>
>> That's fine. I'm just talking about the special case for None that
>> has existed in Python for years - and for a good reason.
>
> How hard is it to implement your own "missing" object which has the
> desired semantics? Why should something as fundamental as None have it?

Because None is already special, has had this feature for a very
long time and there's no apparent reason to move the feature to
some other special object.

Also, having each module or project invent its own NULL-like
object will not make things better for anyone, it would only
introduce new problems.

I don't see any benefit from the removal of the special property
of None in Python 3.0.

--
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source (#1, Nov 11 2008)
>>> Python/Zope Consulting and Support ... http://www.egenix.com/
>>> mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/
>>> mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/
________________________________________________________________________

:::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,MacOSX for free ! ::::


eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48
D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
Registered at Amtsgericht Duesseldorf: HRB 46611

Antoine Pitrou

unread,
Nov 11, 2008, 9:27:57 AM11/11/08
to pytho...@python.org
M.-A. Lemburg <mal <at> egenix.com> writes:
>
> NULLs are a fact in life, not only in SQL, but also in numerics and
> statistics. You often don't want a complex calculation or query to
> fail just because a few input values are not available.

But it only works in the case where you only do comparisons, and where
defaulting to "smaller than everything" is the right behaviour. Would you want
"None + 1" to return either 1 or None, rather than raising TypeError?

Also, it is trivial to write a list comprehension or generator expression that
filters all None values before doing the complex calculation or query.


Antoine.

Victor Stinner

unread,
Nov 11, 2008, 9:38:43 AM11/11/08
to pytho...@python.org
Le Tuesday 11 November 2008 15:21:03 M.-A. Lemburg, vous avez écrit :
> Because None is already special, has had this feature for a very
> long time (...)

Yeah, Python3 breaks compatibility by removing old dummy behaviour like
comparaison between bytes and characters, or between an integer an None ;-)

I like the new behaviour, it helps to detect bugs earlier ! I hope that
the -bb option will be enabled by default in Python 2.7 :-)

You can use an explicit comparaison to None as workaround for your problem:
(x is None) or (x < y)

--
Victor Stinner aka haypo
http://www.haypocalc.com/blog/

M.-A. Lemburg

unread,
Nov 11, 2008, 9:44:55 AM11/11/08
to Daniel Stutzbach, Python 3000
On 2008-11-11 15:22, Daniel Stutzbach wrote:

> On Tue, Nov 11, 2008 at 7:06 AM, M.-A. Lemburg <m...@egenix.com> wrote:
>
>> Why was the special case for None being "smaller" than all other
>> objects in Python removed from Python 3.0 ? (see object.c in Py2.x)
>>
>
> It wasn't true in Python 2.5, either. Observe:
>
> Cashew:~/pokersleuth/tracker$ python2.5
> Python 2.5 (r25:51908, Feb 26 2007, 08:19:26)
> [GCC 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)] on cygwin
> Type "help", "copyright", "credits" or "license" for more information.
>>>> import datetime
>>>> now = datetime.datetime.now()
>>>> now < None
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> TypeError: can't compare datetime.datetime to NoneType

You're right, it's a bit unfortunate, that the special casing
is only applied as fall back mechanism in Python 2.x and that's
not always triggered when dealing with objects implementing
rich comparisons.

However, it does work for all the basic built-in types in Python,
such as strings, numbers, lists, tuples, dicts, etc.

Guido van Rossum

unread,
Nov 11, 2008, 12:09:11 PM11/11/08
to M.-A. Lemburg, Python 3000
We're not going to add the "feature" back that None compares smaller
than everything. It's a slippery slope that ends with all operations
involving None returning None -- I've seen a proposal made in all
earnestness requesting that None+42 == None, None() == None, and so
on. This Nonesense was wisely rejected; a whole slew of
early-error-catching would have gone out of the window. It's the same
with making None smaller than everything else. For numbers, you can
already use -inf; for other types, you'll have to invent your own
Smallest if you need it.

In short, I'll have None of it.

--
--Guido van Rossum (home page: http://www.python.org/~guido/)

Terry Reedy

unread,
Nov 11, 2008, 12:58:37 PM11/11/08
to pytho...@python.org
M.-A. Lemburg wrote:
> Why was the special case for None being "smaller" than all other
> objects in Python removed from Python 3.0 ? (see object.c in Py2.x)

For one thing, it is only smallest when it controls the comparison.

>>> class c(object):
... def __lt__(s,o): return True
...
>>> cc = c()
>>> cc < None
True

Of course,

>>> None < cc
True

Which means that both [cc, None] and [None, cc] are sorted (assuming it
only uses < comparison).

Terry Jan Reedy

Tim Peters

unread,
Nov 11, 2008, 1:20:26 PM11/11/08
to pytho...@python.org
[M.-A. Lemburg]
> ...

> That's fine. I'm just talking about the special case for None that
> has existed in Python for years - and for a good reason.

That's overstating it a bit ;-) In Python 1.5.1, comparisons were
changed so that objects of numeric types compared smaller than objects
of non-numeric types, and then 0 < None was true, not None < 0 (which
became true substantially later). The reason for that change is
explained in Misc/HISTORY (it was an attempt to preserve transitivity
across chains of mixed-type comparisons).

Later, during the move to rich comparisons, I was hacking the code in
the same room with Guido, and realized something special had to be
done with None.

"Hey, Guido, what should we do about mixed-type comparisons against None?"

"Hmm ... what do you think?"

"Hmm ... OK, let's make None smaller than other types."

"Why?"

"Oh, why not?"

"Good enough -- but let's not document it -- it's an arbitrary
implementation detail."

"Of course!"

In any case, we thought this was so arbitrary that we didn't hesitate
to break that, up until that time, "0 < None" /had/ been true "for
years - and for a good reason" ;-)

not-all-good-reasons-are-particularly-good-ly y'rs - tim

M.-A. Lemburg

unread,
Nov 11, 2008, 3:28:59 PM11/11/08
to Guido van Rossum, Python 3000
On 2008-11-11 18:09, Guido van Rossum wrote:
> We're not going to add the "feature" back that None compares smaller
> than everything. It's a slippery slope that ends with all operations
> involving None returning None -- I've seen a proposal made in all
> earnestness requesting that None+42 == None, None() == None, and so
> on. This Nonesense was wisely rejected; a whole slew of
> early-error-catching would have gone out of the window.

I was suggesting None of that.

> It's the same
> with making None smaller than everything else. For numbers, you can
> already use -inf; for other types, you'll have to invent your own
> Smallest if you need it.

No, that doesn't work: -inf is a perfectly valid number, None isn't.

Same for strings: '' would be a valid string that compares smaller
than all others, None isn't.

Furthermore, if you get a None value from some database or data set,
you don't want to replace that special n/a value with a valid number
or string - since you'd lose round-trip safety. In some cases you
don't even know whether the item was supposed to be a number or e.g.
a string, so there is no obvious choice for a replacement.

Looks like data processing algorithms written for Python3 will have
to start using key functions throughout or end up requiring lots of
if-elif-elses to deal gracefully with the different combinations
of comparison failures.

Oh well, another surprise to add to the Python 3k list of surprises.

And here's another one:

>>> None < None


Traceback (most recent call last):
File "<stdin>", line 1, in <module>

TypeError: unorderable types: NoneType() < NoneType()
>>> None is None
True
>>> None == None
True
>>> None > None


Traceback (most recent call last):
File "<stdin>", line 1, in <module>

TypeError: unorderable types: NoneType() > NoneType()
>>> None != None
False

Two values that compare equal to each other (and are in fact identical),
yet cannot be compared less-than or greater-than.

This would make sense if you think of None as meaning "anything
and/or nothing", since the left side None could stand for
a different None than the right one, but then you could apply the
same logic to inf:

>>> inf = float('inf')
>>> inf < inf
False
>>> inf is inf
True
>>> inf == inf
True
>>> inf > inf
False
>>> inf != inf
False

In this case you don't get any errors.

Note all of this has to be seen from a user perspective, not from
a CPython implementors perspective.

--
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source (#1, Nov 11 2008)
>>> Python/Zope Consulting and Support ... http://www.egenix.com/
>>> mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/
>>> mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/
________________________________________________________________________

:::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,MacOSX for free ! ::::


eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48
D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
Registered at Amtsgericht Duesseldorf: HRB 46611

Greg Ewing

unread,
Nov 11, 2008, 5:27:51 PM11/11/08
to Python 3000
M.-A. Lemburg wrote:

> And here's another one:

> ...


> Two values that compare equal to each other (and are in fact identical),
> yet cannot be compared less-than or greater-than.

That's not particularly surprising -- complex numbers have
been like that for a long time. The only surprise, if any,
is that more types are becoming that way.

--
Greg

Antoine Pitrou

unread,
Nov 11, 2008, 6:09:14 PM11/11/08
to pytho...@python.org
M.-A. Lemburg <mal <at> egenix.com> writes:
>
> >>> None > None
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> TypeError: unorderable types: NoneType() > NoneType()
> >>> None != None
> False
>
> Two values that compare equal to each other (and are in fact identical),
> yet cannot be compared less-than or greater-than.

The error message is clear: "unorderable types". Having some types support an
equivalence relation (e.g. "equality") but no intuitive total order relation is
hardly a surprise. As someone said, complex numbers are an example of that (not
only in Python, but in real life).

> This would make sense if you think of None as meaning "anything
> and/or nothing", since the left side None could stand for
> a different None than the right one, but then you could apply the
> same logic to inf:

inf is a float instance, and as such supports ordering. I don't see how it
invalidates None *not* supporting an order relation, since None isn't a float
instance and doesn't pretend to be usable as a number (or as anything supporting
ordering, for that matter).

Greg Ewing

unread,
Nov 11, 2008, 5:00:45 PM11/11/08
to pytho...@python.org
M.-A. Lemburg wrote:
> On 2008-11-11 14:28, Antoine Pitrou wrote:
>
>>But why should "n/a" (or "missing", or "undefined") imply "smaller than
>>everything else"?
>
> It's just a convention based on viewing None as "nothing" or the
> empty set.

It would be possible to implement this convention in the
sort method, without making it a feature of comparisons
in general.

SQL does something similar -- while nulls sort before
everything else, the result of null < something is null,
not true.

--
Greg

M.-A. Lemburg

unread,
Nov 12, 2008, 5:01:52 AM11/12/08
to Tim Peters, pytho...@python.org

Thanks for that bit of history :-)

With "good reason" I meant special casing None w/r to putting
it in a fixed place somewhere into the ordering scheme. The important
aspect is getting it in there, not the exact position it takes.

None could also compare larger than any other object, or smaller
than all objects with type names starting with a 'P' and larger than
all objects with type names starting with an 'O'. You just need to
get it in there somewhere in order to have comparisons with None
not fail with an exception.

--
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source (#1, Nov 12 2008)


>>> Python/Zope Consulting and Support ... http://www.egenix.com/
>>> mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/
>>> mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/
________________________________________________________________________

:::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,MacOSX for free ! ::::


eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48
D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
Registered at Amtsgericht Duesseldorf: HRB 46611

M.-A. Lemburg

unread,
Nov 12, 2008, 5:44:11 AM11/12/08
to Antoine Pitrou, pytho...@python.org
On 2008-11-12 00:09, Antoine Pitrou wrote:
> M.-A. Lemburg <mal <at> egenix.com> writes:
>>>>> None > None
>> Traceback (most recent call last):
>> File "<stdin>", line 1, in <module>
>> TypeError: unorderable types: NoneType() > NoneType()
>>>>> None != None
>> False
>>
>> Two values that compare equal to each other (and are in fact identical),
>> yet cannot be compared less-than or greater-than.
>
> The error message is clear: "unorderable types". Having some types support an
> equivalence relation (e.g. "equality") but no intuitive total order relation is
> hardly a surprise. As someone said, complex numbers are an example of that (not
> only in Python, but in real life).

The difference is that None is a singleton, so the set of all
None type instances is {None}. You always have an intuitive total order
relation on one element sets: the identity relation.

>> This would make sense if you think of None as meaning "anything
>> and/or nothing", since the left side None could stand for
>> a different None than the right one, but then you could apply the
>> same logic to inf:
>
> inf is a float instance, and as such supports ordering. I don't see how it
> invalidates None *not* supporting an order relation, since None isn't a float
> instance and doesn't pretend to be usable as a number (or as anything supporting
> ordering, for that matter).

Right, but you're taking the view of a CPython developer. You
need to view this as Python user.

In real (math) life, inf is a different type of number than regular floats,
ints or complex numbers and has a special meaning depending on the context
in which you use it. The relationship is much like that of None to all
other Python objects.

--
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source (#1, Nov 12 2008)


>>> Python/Zope Consulting and Support ... http://www.egenix.com/
>>> mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/
>>> mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/
________________________________________________________________________

:::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,MacOSX for free ! ::::


eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48
D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
Registered at Amtsgericht Duesseldorf: HRB 46611

Greg Ewing

unread,
Nov 12, 2008, 6:07:09 AM11/12/08
to pytho...@python.org
M.-A. Lemburg wrote:

> The difference is that None is a singleton, so the set of all
> None type instances is {None}. You always have an intuitive total order
> relation on one element sets: the identity relation.

I don't see this having much practical consequence, though,
since sorting members of a 1-element set isn't a very
useful thing to do.

--
Greg

Antoine Pitrou

unread,
Nov 12, 2008, 10:10:29 AM11/12/08
to pytho...@python.org
M.-A. Lemburg <mal <at> egenix.com> writes:
>
> The difference is that None is a singleton, so the set of all
> None type instances is {None}. You always have an intuitive total order
> relation on one element sets: the identity relation.

But it's not what you are asking for. You are asking for None to support ordered
comparison with objects of other types, which is completely different.

Having None be comparable with itself for ordered comparisons is certainly
possible, but it's also completely useless if None doesn't compare with other
types, which is what we are talking about.

> Right, but you're taking the view of a CPython developer. You
> need to view this as Python user.

No, I'm taking the view of an user. inf is usable as a float object and as such
supports many of the same operations as other float objects. None obviously
doesn't and doesn't claim to. I don't see how this is a CPython-centric point of
view.

> In real (math) life, inf is a different type of number than regular floats,
> ints or complex numbers and has a special meaning depending on the context
> in which you use it.

Well, in real life, inf isn't a number at all. It is a notation to indicate the
behaviour of certain sequences or functions when some of their arguments tends
to a certain "value" (either infinite, or a singular point for which the
function or sequence is not defined). Making inf usable as a number is a way to
make more accessible some useful properties of limits, at the price of
notational abuse. (*)

But there's still no analogy with None. None has nothing to do with algebra,
limits, neighbourings or closures. It cannot be defined as the limit of a
particular function when of its arguments approaches either infinity or a
singular point. None is a independent discrete value, not something at the outer
boundary of a continuous set of values.


(*) e.g.:

>>> f = float("inf")
>>> f * f
inf
>>> math.exp(f)
inf
>>> math.log(f)
inf
>>> math.tanh(f)
1.0
>>> math.exp(-f)
0.0
>>> 1 ** f
1.0
>>> 0 ** f
0.0

It is not complete though :

>>> 2 ** f


Traceback (most recent call last):
File "<stdin>", line 1, in <module>

OverflowError: (34, 'Numerical result out of range')
>>> f ** 2


Traceback (most recent call last):
File "<stdin>", line 1, in <module>

OverflowError: (34, 'Numerical result out of range')

Regards

Antoine.

Guido van Rossum

unread,
Nov 12, 2008, 2:19:47 PM11/12/08
to Tim Peters, pytho...@python.org

Hah! I can vouch that this is pretty much how it went. It's a good
thing our process has changed a bit; in today's world this would have
required a PEP, and for good reason. I would have fought the proposal
if it had been proposed as a new feature for Python 3000.

welcome-back-tim-ly y'rs,

--
--Guido van Rossum (home page: http://www.python.org/~guido/)

Bruce Leban

unread,
Nov 12, 2008, 2:52:41 PM11/12/08
to Greg Ewing, pytho...@python.org
On Tue, Nov 11, 2008 at 2:00 PM, Greg Ewing <greg....@canterbury.ac.nz> wrote:
M.-A. Lemburg wrote:
On 2008-11-11 14:28, Antoine Pitrou wrote:

But why should "n/a" (or "missing", or "undefined") imply "smaller than
everything else"?

It's just a convention based on viewing None as "nothing" or the
empty set.

It would be possible to implement this convention in the
sort method, without making it a feature of comparisons
in general.

+1 

None / Missing / undefined should be able to be sorted with other data. If this requires adding an optional parameter to sort, I'm fine with that. Note that this works with strings today:

x = "abc" 
y = "abcd"
x < y

note that x[3] is undefined and the comparison operator (and sorting) automatically places x before y when all other elements of x and y are equal. Likewise if I created a comparison method for a class I would probably order

C(a=1) < C(a=2) < C(a=2, b=3)

I understand why you don't want to make None comparison work generally for the < operator.

--- Bruce

Marcin 'Qrczak' Kowalczyk

unread,
Nov 12, 2008, 4:13:50 PM11/12/08
to pytho...@python.org
2008/11/11 Greg Ewing <greg....@canterbury.ac.nz>:

> It would be possible to implement this convention in the
> sort method, without making it a feature of comparisons
> in general.

Until someone wishes to sort a list of some objects by key, where the
keys can be (1, None) compared with (1, 3). This will be confusing
because None compared with 3 would work.

--
Marcin Kowalczyk
qrc...@knm.org.pl
http://qrnik.knm.org.pl/~qrczak/

Nick Coghlan

unread,
Nov 12, 2008, 4:28:56 PM11/12/08
to Bruce Leban, pytho...@python.org
Bruce Leban wrote:
>
>
> On Tue, Nov 11, 2008 at 2:00 PM, Greg Ewing <greg....@canterbury.ac.nz
> <mailto:greg....@canterbury.ac.nz>> wrote:
>
> M.-A. Lemburg wrote:
>
> On 2008-11-11 14:28, Antoine Pitrou wrote:
>
> But why should "n/a" (or "missing", or "undefined") imply
> "smaller than
> everything else"?
>
>
> It's just a convention based on viewing None as "nothing" or the
> empty set.
>
>
> It would be possible to implement this convention in the
> sort method, without making it a feature of comparisons
> in general.
>
>
> +1

Adding a shorthand way of filtering out or otherwise permitting "None"
entries in sorted()/list.sort() certainly has a greater chance of
acceptance than bringing back ordering comparisons to None in general.

As Marcin points out though, there would be potential issues with such
an idea that may even need a PEP to thrash out (mainly the "what happens
for containers" question that he brings up, but there may be other
pitfalls as well).

Application specific key or comparison functions with their own ideas on
how to handle None really don't sound like a bad idea to me.

Cheers,
Nick.

--
Nick Coghlan | ncog...@gmail.com | Brisbane, Australia
---------------------------------------------------------------

Greg Ewing

unread,
Nov 12, 2008, 7:54:47 PM11/12/08
to pytho...@python.org
Marcin 'Qrczak' Kowalczyk wrote:
> 2008/11/11 Greg Ewing <greg....@canterbury.ac.nz>:
>
>> It would be possible to implement this convention in the
>> sort method
>
> Until someone wishes to sort a list of some objects by key, where the
> keys can be (1, None) compared with (1, 3).

Yes, I thought of that shortly after posting. Lists and
tuples could be special-cased as well, although someone
is inevitably going to be surprised when their favourite
sequence type doesn't get included in the special
treatment.

However, covering lists and tuples would cover the vast
majority of use cases, I think. So perhaps the best
thing would be to provide this as an option, defaulting
to false, and with the limitations clearly documented.
If someone has a use case not covered by it, they just
have to provide their own key function.

Another approach would be to define a protocol for
comparison-for-sorting, which custom types could implement
if they wanted.

--
Greg

M.-A. Lemburg

unread,
Nov 13, 2008, 6:35:56 AM11/13/08
to Antoine Pitrou, pytho...@python.org
On 2008-11-12 16:10, Antoine Pitrou wrote:
> M.-A. Lemburg <mal <at> egenix.com> writes:
>> The difference is that None is a singleton, so the set of all
>> None type instances is {None}. You always have an intuitive total order
>> relation on one element sets: the identity relation.
>
> But it's not what you are asking for. You are asking for None to support ordered
> comparison with objects of other types, which is completely different.
>
> Having None be comparable with itself for ordered comparisons is certainly
> possible, but it's also completely useless if None doesn't compare with other
> types, which is what we are talking about.

I should have probably made it clearer in my posting:

Having None < None fail is another different (and a lot more
insignificant) problem.

It would be solved by having None added to a consistent Python
object ordering scheme, but is not a consequence of not having
a consistent general object ordering scheme.

So far, I haven't heard a single argument for why not having None
participate in an ordering scheme is a good strategy to use, except
that it's pure. IMHO, practicality beats purity in this special
case.

Anyway, like I said: it's one more thing to add to the list of
surprises in Python 3.0.

--
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source (#1, Nov 13 2008)


>>> Python/Zope Consulting and Support ... http://www.egenix.com/
>>> mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/
>>> mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/
________________________________________________________________________

:::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,MacOSX for free ! ::::


eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48
D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
Registered at Amtsgericht Duesseldorf: HRB 46611

Guido van Rossum

unread,
Nov 13, 2008, 10:15:14 AM11/13/08
to M.-A. Lemburg, pytho...@python.org, Antoine Pitrou
On Thu, Nov 13, 2008 at 3:35 AM, M.-A. Lemburg <m...@egenix.com> wrote:
> Anyway, like I said: it's one more thing to add to the list of
> surprises in Python 3.0.

I'm happy to do so. I expect that over time it won't be an issue.

--
--Guido van Rossum (home page: http://www.python.org/~guido/)

Tim Peters

unread,
Nov 13, 2008, 1:55:52 PM11/13/08
to pytho...@python.org
[M.-A. Lemburg]
> ...

> So far, I haven't heard a single argument for why not having None
> participate in an ordering scheme is a good strategy to use, except
> that it's pure.

I've tracked down plenty of program logic errors that would have been
discovered more easily if comparing None to (mostly, but among others)
integers and strings had raised an exception instead of returning a
meaningless true/false result. Perhaps you haven't. For those who
have, the attraction to making comparisons with None refuse to return
nonsense silently is both obvious and visceral.


> IMHO, practicality beats purity in this special case.

If hiding program logic errors is practical, sure ;-)

there-is-no-behavior-no-matter-how-bizarre-someone-won't
come-to-rely-on-ly y'rs - tim

Bruce Leban

unread,
Nov 13, 2008, 2:15:23 PM11/13/08
to Tim Peters, pytho...@python.org
I think the behavior of NaN in comparisons is more confusing:

>>> sorted([1,nan,2])
[1, nan, 2]
>>> sorted([2,nan,1])
[2, nan, 1]
>>> sorted([2,None,1])
Traceback (most recent call last):
  File "<pyshell#28>", line 1, in <module>
    sorted([2,None,1])
TypeError: unorderable types: NoneType() < int()

At least the third case is clear that I shouldn't have done that. The way nan works, the results of sorting where one of the values is nan is unpredictable and useless.

Yes, I know the rules about how NaN values behave in comparisons. Notwithstanding that, sorting could use a different comparison rule imposing a total ordering: -inf, ..., inf, nan as some other systems do.

--- Bruce


Jeffrey Yasskin

unread,
Nov 13, 2008, 4:01:44 PM11/13/08
to Bruce Leban, pytho...@python.org
Be glad you're not programming in C++ then, where trying to sort NaN
can cause segfaults!

More seriously, I think using the following function as the sort key
will make sort do what you want:

def SortNoneFirstAndNanLast(x):
if x is None:
return (1, x)
if isnan(x):
return (3, x)
return (2, x)

No need to modify either sort() or <.

> http://mail.python.org/mailman/options/python-3000/jyasskin%40gmail.com
>
>

--
Namasté,
Jeffrey Yasskin
http://jeffrey.yasskin.info/


_______________________________________________
Python-3000 mailing list
Pytho...@python.org
http://mail.python.org/mailman/listinfo/python-3000

Unsubscribe: http://mail.python.org/mailman/options/python-3000/python-3000-garchive-63646%40googlegroups.com

Daniel Stutzbach

unread,
Nov 11, 2008, 9:22:29 AM11/11/08
to M.-A. Lemburg, Python 3000
On Tue, Nov 11, 2008 at 7:06 AM, M.-A. Lemburg <m...@egenix.com> wrote:
Why was the special case for None being "smaller" than all other
objects in Python removed from Python 3.0 ? (see object.c in Py2.x)
It wasn't true in Python 2.5, either.  Observe:

Cashew:~/pokersleuth/tracker$ python2.5
Python 2.5 (r25:51908, Feb 26 2007, 08:19:26)
[GCC 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime
>>> now = datetime.datetime.now()
>>> now < None
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't compare datetime.datetime to NoneType


Right now to get the desired semantics, I implement a custom AlwaysLeast and/or AlwaysGreatest singletons for whatever type I'm dealing with.  It's a bit of  of a pain.  My use cases are all along the following lines:

class TimeSpan:
   def __init__(self):
        self.earliest = AlwaysGreatest
        self.latest = AlwaysLeast

    def update(self, v):
        self.earliest = min(self.earliest, v)
        self.latest = max(self.latest, v)
--
Daniel Stutzbach, Ph.D.
http://www.barsoom.org/~agthorr

Josiah Carlson

unread,
Nov 17, 2008, 5:50:06 PM11/17/08
to Greg Ewing, pytho...@python.org
On Wed, Nov 12, 2008 at 3:07 AM, Greg Ewing <greg....@canterbury.ac.nz> wrote:
> M.-A. Lemburg wrote:
>
>> The difference is that None is a singleton, so the set of all
>> None type instances is {None}. You always have an intuitive total order
>> relation on one element sets: the identity relation.
>
> I don't see this having much practical consequence, though,
> since sorting members of a 1-element set isn't a very
> useful thing to do.

This discussion smells like a re-hashing of the PEP 326 discussion.

While I will (momentarily) lament None's passing as a (more or less)
minimal object in Python, I believe that an explicit maximum and
minimum value are much preferred over None. And as I stated
previously, having a single implementation of the one true maximum or
minimum value is much preferable to everyone writing their own
(especially with respect to potential bugs).

If a max/min value is desired (votes for None comparing smaller are a
vote for a max/min value, just with a specific previously-established
spelling), then a single implementation should exist. But then we get
back into the same discussion that was had before: do we want them,
and if so, what do we call them?

- Josiah

Reply all
Reply to author
Forward
0 new messages