Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Question about None

7 views
Skip to first unread message

Paul LaFollette

unread,
Jun 12, 2009, 10:05:29 AM6/12/09
to pytho...@python.org
Kind people,

Using Python 3.0 on a Gatesware machine (XP).
I am building a class in which I want to constrain the types that can
be stored in various instance variables. For instance, I want to be
certain that self.loc contains an int. This is straightforward (as
long as I maintain the discipline of changing loc through a method
rather than just twiddling it directly.

def setLoc(lo):
assert isinstance(lo, int), "loc must be an int"
self.loc = lo

does the trick nicely.

However, I also want to constrain self.next to be either an instance
of class Node, or None. I would think that the following should work
but it doesn't.

def setNext(nxt):
assert isinstance(nxt, (Node, NoneType)), "next must be a Node"
self.next = nxt

since type(Node) responds with <class, 'NoneType'> but the assertion
above gives "name 'NoneType' is not defined" suggesting that NoneType
is some sort of quasi-class.

def setNext(nxt):
assert nxt==None or isinstance(nxt, Node), "next must be a Node"
self.next = nxt

works ok, but it's uglier than it ought to be.

So, I have three questions.

1) Why doesn't isinstance(nxt, (Node, NoneType)) work?
2) is their a less ugly alternative that what I am using?
3) (this is purely philosophical but I am curious) Would it not be
more intuitive if
isinstance(None, <anything at all>) returned true?

Thank you for your kind attention.
Paul

Javier Collado

unread,
Jun 12, 2009, 10:22:05 AM6/12/09
to Paul LaFollette, pytho...@python.org
Hello,

This should work for you:

In [1]: import types

In [2]: isinstance(None, types.NoneType)
Out[2]: True


Best regards,
Javier

2009/6/12 Paul LaFollette <paul.la...@gmail.com>:

> --
> http://mail.python.org/mailman/listinfo/python-list
>

Christian Heimes

unread,
Jun 12, 2009, 10:32:27 AM6/12/09
to pytho...@python.org
Paul LaFollette schrieb:

> Kind people,
>
> Using Python 3.0 on a Gatesware machine (XP).
> I am building a class in which I want to constrain the types that can
> be stored in various instance variables. For instance, I want to be
> certain that self.loc contains an int. This is straightforward (as
> long as I maintain the discipline of changing loc through a method
> rather than just twiddling it directly.
>
> def setLoc(lo):
> assert isinstance(lo, int), "loc must be an int"
> self.loc = lo
>
> does the trick nicely.
>
> However, I also want to constrain self.next to be either an instance
> of class Node, or None. I would think that the following should work
> but it doesn't.
>
> def setNext(nxt):
> assert isinstance(nxt, (Node, NoneType)), "next must be a Node"
> self.next = nxt

How about the canonical way to check if an object is None?

assert Node is None

None is a singleton. Python guarantees that there is exactly one None
object and on this account only one instance of NoneType. In Python 3.x
you can't even overwrite the global variable None. User code shouldn't
use NoneType at all.

>>> type(None)
<class 'NoneType'>
>>> type(None)()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot create 'NoneType' instances
>>> None = 1
File "<stdin>", line 1
SyntaxError: assignment to keyword

The singletons True and False have a similar behavior. It's not possible
to overwrite them as well. The bool type always returns either the
singleton True or the singleton False.

>>> True = False
File "<stdin>", line 1
SyntaxError: assignment to keyword
>>> type(True)
<class 'bool'>
>>> type(True) is bool
True
>>> bool(42)
True

Bruno Desthuilliers

unread,
Jun 12, 2009, 10:45:28 AM6/12/09
to
Paul LaFollette a �crit :

> Kind people,
>
> Using Python 3.0 on a Gatesware machine (XP).
> I am building a class in which I want to constrain the types that can
> be stored in various instance variables.

This somehow goes against the whole philosophy of dynamic typing Python
is based upon... But there are indeed cases where it makes sense and I
assume you know what you're doing !-)

> For instance, I want to be
> certain that self.loc contains an int. This is straightforward (as
> long as I maintain the discipline of changing loc through a method
> rather than just twiddling it directly.
>
> def setLoc(lo):
> assert isinstance(lo, int), "loc must be an int"
> self.loc = lo
>
> does the trick nicely.

Did you considered using properties (or custom descriptors) instead ?

(snip - others already answered)

Jeff McNeil

unread,
Jun 12, 2009, 10:55:41 AM6/12/09
to
On Jun 12, 10:05 am, Paul LaFollette <paul.lafolle...@gmail.com>
wrote:

1. The problem is described clearly by that Exception. The 'NoneType'
name isn't bound to any objects at that current scope. I know that
with 2.6, you can import 'types.NoneType' but I don't believe the 3.0
types module includes NoneType. Someone else will have to clarify
that as I don't have 3.0 installed.

2. A less ugly alternative? You could use the accepted method of
testing against None:

if var is None:
do_stuff()

The use of the 'is' operator checks whether objects are exactly the
same (id(var) == id(None)) as opposed to 'isinstance' or '==.'

You might also try defining descriptors in order to make your type
checks slightly more transparent. That might be confusing to other
users of your class, though. Not many people expect a TypeError from
an attribute assignment.

3. None is an instance of NoneType. Why should isinstance return True
when it's tested against other types?

HTH,

Jeff
mcjeff.blogspot.com

Javier Collado

unread,
Jun 12, 2009, 11:26:15 AM6/12/09
to Jeff McNeil, pytho...@python.org
Hello,

You're right, types.NoneType is not available in python 3.0, I wasn't
aware of that change. Thanks for pointing it out.

Best regards,
Javier

2009/6/12 Jeff McNeil <je...@jmcneil.net>:

> --
> http://mail.python.org/mailman/listinfo/python-list
>

Jean-Michel Pichavant

unread,
Jun 12, 2009, 11:36:37 AM6/12/09
to Paul LaFollette, pytho...@python.org

> def setNext(nxt):
> assert nxt==None or isinstance(nxt, Node), "next must be a Node"
> self.next = nxt
>
> works ok, but it's uglier than it ought to be.
>
>
I don't find it that ugly. It's accurate, easy to read and understand.
"What else ?" would say a famous coffee representative.
If you like perfection, replace nxt==None by nxt is None.

Jean-Michel

Terry Reedy

unread,
Jun 12, 2009, 12:32:25 PM6/12/09
to pytho...@python.org
Paul LaFollette wrote:

> since type(Node) responds with <class, 'NoneType'> but the assertion
> above gives "name 'NoneType' is not defined" suggesting that NoneType
> is some sort of quasi-class.

add NoneType = type(None) before using Nonetype

Robert Kern

unread,
Jun 12, 2009, 2:20:44 PM6/12/09
to pytho...@python.org
On 2009-06-12 09:05, Paul LaFollette wrote:
> Kind people,
>
> Using Python 3.0 on a Gatesware machine (XP).
> I am building a class in which I want to constrain the types that can
> be stored in various instance variables. For instance, I want to be
> certain that self.loc contains an int. This is straightforward (as
> long as I maintain the discipline of changing loc through a method
> rather than just twiddling it directly.

You may want to consider using Enthought's Traits package (disclosure: I work
for Enthought).

http://pypi.python.org/pypi/Traits/

Type-checking attributes is not my favorite feature of Traits (I try to avoid
using this feature if I can avoid it), but it is designed for precisely your use
cases.


In [2]: %cpaste
Pasting code; enter '--' alone on the line to stop.
:from enthought.traits.api import Float, HasTraits, Instance, Int, This
:
:class FancyClass(HasTraits):
: """ An example traited class.
: """
: x = Float(10.0)
: y = Int(-20)
:
:class Node(HasTraits):
: """ A node in a single-linked list.
: """
:
: # The location of this Node.
: loc = Int(0)
:
: # The next Node. This() is a special trait that accepts instances of
: # this class, or None.
: next = This()
:
: # The data attached to the Node. It will accept instances of FancyClass
: # or None.
: data = Instance(FancyClass)
:
:
:--

In [3]: n = Node()

In [4]: n.next

In [5]: n.data

In [6]: n.loc
Out[6]: 0

In [7]: fc = FancyClass(x=15.0)

In [8]: fc.x
Out[8]: 15.0

In [9]: fc.y
Out[9]: -20

In [10]: fc.y = 'a string'
---------------------------------------------------------------------------
TraitError Traceback (most recent call last)

/Users/rkern/<ipython console> in <module>()

/Users/rkern/svn/et/Traits/enthought/traits/trait_handlers.pyc in error(self,
object, name, value)
173 """
174 raise TraitError( object, name, self.full_info( object, name,
value ),
--> 175 value )
176
177 def arg_error ( self, method, arg_num, object, name, value ):

TraitError: The 'y' trait of a FancyClass instance must be an integer, but a
value of 'a string' <type 'str'> was specified.

In [11]: n.data = fc

In [12]: n.data = None

In [13]: n.data = n
---------------------------------------------------------------------------
TraitError Traceback (most recent call last)

/Users/rkern/<ipython console> in <module>()

/Users/rkern/svn/et/Traits/enthought/traits/trait_handlers.pyc in error(self,
object, name, value)
173 """
174 raise TraitError( object, name, self.full_info( object, name,
value ),
--> 175 value )
176
177 def arg_error ( self, method, arg_num, object, name, value ):

TraitError: The 'data' trait of a Node instance must be a FancyClass or None,
but a value of <__main__.Node object at 0x17999c0> <class '__main__.Node'> was
specified.

In [14]: n.next = Node(loc=1)

In [15]: n.next
Out[15]: <__main__.Node at 0x1892e70>

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco

Steven D'Aprano

unread,
Jun 13, 2009, 2:29:34 AM6/13/09
to
Paul LaFollette wrote:

> 3) (this is purely philosophical but I am curious) Would it not be
> more intuitive if
> isinstance(None, <anything at all>) returned true?

Good grief no!!!

None is an object. It has a type, NoneType. It's *not* a string, or a float,
or an int, or a list, so why would you want isinstance() to *lie* and say
that it is?


Python is good for testing these sorts of ideas:

>>> _isinstance = isinstance
>>> def isinstance(obj, type):
... if obj is None: return True
... return _isinstance(obj, type)
...
>>> x = "parrot"
>>> if isinstance(x, str):
... print x.upper()
...
PARROT
>>> x = None
>>> if isinstance(x, str): print x.upper()
...


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

AttributeError: 'NoneType' object has no attribute 'upper'


--
Steven

Steven D'Aprano

unread,
Jun 13, 2009, 2:34:00 AM6/13/09
to
Jean-Michel Pichavant wrote:

>
>> def setNext(nxt):
>> assert nxt==None or isinstance(nxt, Node), "next must be a Node"
>> self.next = nxt
>>
>> works ok, but it's uglier than it ought to be.
>>
>>
> I don't find it that ugly. It's accurate, easy to read and understand.

Actually, it's inaccurate. There are *three* bugs in that code, two in the
same line. (Admittedly, one of the three is closer to a nitpick than a
bug.) You already allude to one of them:


> "What else ?" would say a famous coffee representative.
> If you like perfection, replace nxt==None by nxt is None.

Delete the "if you like perfection" part. Testing for equality against None
in this case is simply *wrong*. Arbitrary objects can be made to test equal
to None -- for instance, the Null object pattern. Unless you wish to allow
such "null" objects as well as None, then "nxt == None" does not do what
you want to do: it fails to reject some things that should be rejected.

The second bug is that the line uses assert for runtime value/type testing.
That's bad, because asserts are disabled when you run Python with the
optimisation flag. That means that your program will stop performing the
necessary test.

assert is for testing program logic[1], not argument testing. If you're ever
tempted to write an if...elif...else block that includes the comment, "this
should never happen, but just in case" then you have a good candidate for
an assert. A good use for assert is for checking that your program logic is
correct, not for testing user-arguments:

def process(text):
for word in text.split():
word = somefunction(word)
# say that it's important that word contains no newlines
# you're sure that somefunction() *won't* introduce any,
# but you want to be positive
assert "\n" not in word
do_something_with(word)

In this case, assert is appropriate: the code *should* work if the assert is
disabled, but it will give you some protection from bugs in your code.
Whenever you're tempted to use assert, ask yourself "if I deleted this test
from my code, would the program still run correctly?". If the answer
is "possibly not", then don't use an assert.


The third bug (the nitpick) is a bug in the API: you name the argument "nxt"
with no e, but in the error message, you call it "next" with an e. The fact
that any intelligent person should be able to guess what parameter the
error is referring to doesn't make it less wrong.

So, fixing the three issues:

def setNext(next):
if not (next is None or isinstance(next, Node)):
raise ValueError("next must be a Node")
self.next = next


[1] Arguably, it's also good for poor-man's unit testing when you're too
lazy to write proper tests.

--
Steven

Terry Reedy

unread,
Jun 13, 2009, 12:27:45 PM6/13/09
to pytho...@python.org
Steven D'Aprano wrote:
[ snip excellent discussion of proper use of assert]

> The third bug (the nitpick) is a bug in the API: you name the argument "nxt"
> with no e, but in the error message, you call it "next" with an e. The fact
> that any intelligent person should be able to guess what parameter the
> error is referring to doesn't make it less wrong.
>
> So, fixing the three issues:
>
> def setNext(next):
> if not (next is None or isinstance(next, Node)):
> raise ValueError("next must be a Node")
> self.next = next

[counternit] Of course, next() is a builtin function and some consider
reusing builtin names as bare names (versus attribute names) a bad
habit. I think the OP had a good idea in using a variation, but should
have been consistent.

John Yeung

unread,
Jun 13, 2009, 1:23:38 PM6/13/09
to
On Jun 13, 2:29 am, Steven D'Aprano

<st...@REMOVETHIS.cybersource.com.au> wrote:
> Paul LaFollette wrote:
> > 3) (this is purely philosophical but I am curious)
> > Would it not be more intuitive if
> > isinstance(None, <anything at all>) returned true?
>
> Good grief no!!!
>
> None is an object. It has a type, NoneType. It's *not* a
> string, or a float, or an int, or a list, so why would
> you want isinstance() to *lie* and say that it is?

Because you might want None to behave as though it were nothing at
all.

Paul LaFollette is probably thinking along the lines of formal logic
or set theory. It's a little bit confused because programming isn't
quite the same as math, and so it's a common question when designing
and implementing programming languages how far to take certain
abstractions. In some languages, nil, null, or none will try to
behave as mathematically close to "nothing" (complete absence of
anything) as possible, even though in reality they have to have some
concrete implementation, such as perhaps being a singleton object.
But mathematically speaking, it's intuitive that "nothing" would match
any type.

I find that it's somewhat like the confusion that often occurs
regarding the all() function. Some people are surprised that all([])
returns True, but it's the same logic behind the truth of the
statement "every element of the empty set is an integer". It's also
true that every element of the empty set is a float. Or an elephant.

John

Paul Rubin

unread,
Jun 13, 2009, 1:49:12 PM6/13/09
to
John Yeung <gallium....@gmail.com> writes:
> Because you might want None to behave as though it were nothing at all.

Sure, you might also want strings to behave as if they were ints, but
wishing doesn't make it so.

> But mathematically speaking, it's intuitive that "nothing" would match
> any type.

Completely wrong. The concept you're thinking of in denotational
semantics is called "bottom", but bottom is not a value that functions
can compute and return. It is really the absence of a value. We
would say that a function semantically returns bottom, if calling does
something like loop forever (never return), or it makes the program
crash, or something like that. None is a value which in Haskell has a
particular type. In some other languages, there are None-like values
in more than one type, like in Haskell, for any type there is a
Nothing for the Maybe of that type, but they all are of differing
types, just like Python has an integer 0 and a floating point 0 that
are of differing types.

> I find that it's somewhat like the confusion that often occurs
> regarding the all() function.

It's the other way though, all([])=True makes sense,
isinstance(None,int) does not.

Paul Rubin

unread,
Jun 13, 2009, 1:55:01 PM6/13/09
to
Paul Rubin <http://phr...@NOSPAM.invalid> writes:
> crash, or something like that. None is a value which in Haskell has a

I got ahead of myself, of course I meant Python (the *next* sentence
was going to mention Haskell). The corresponding concept in Haskell
is called Nothing, which lives in a type functor called Maybe. I
don't have time to go into it right now but there is a notion among
language weenies these days that the presence of something like None
(in Python) or Null (in Java, SQL, etc) is a wart in a language and
that it's preferable to have something like Maybe.

John Yeung

unread,
Jun 13, 2009, 4:25:28 PM6/13/09
to
On Jun 13, 1:49 pm, Paul Rubin <http://phr...@NOSPAM.invalid> wrote:

> John Yeung <gallium.arsen...@gmail.com> writes:
> > Because you might want None to behave as though it were
> > nothing at all.
>
> Sure, you might also want strings to behave as if they
> were ints, but wishing doesn't make it so.

I'm not saying that the OP, as a programmer using Python, would wish
that Python's None behaves like nothing. I'm saying that as a
philosophical question, which is how he phrased it, one might want
one's language (perhaps one is designing this language) to have
something that behaves like "nothing", and then call this "None". I
don't think he's saying that the wrong choice was made for Python; I'm
certainly not saying that; it was just a musing.

> > But mathematically speaking, it's intuitive that
> > "nothing" would match any type.
>
> Completely wrong.  The concept you're thinking of in
> denotational semantics is called "bottom", but bottom
> is not a value that functions can compute and return.
> It is really the absence of a value.

I've never heard a mathematician use the term "bottom". It certainly
could be that I just haven't talked to the right types of
mathematicians. I'm not sure it's even relevant. "Denotational
semantics" is specific to computer science. My point was simply that
even an elementary understanding of mathematics (and I'll grant a
naive understanding of computer science as well) might lead someone to
think that it *might* make sense for None to be the name for nothing.

> > I find that it's somewhat like the confusion that often
> > occurs regarding the all() function.
>
> It's the other way though, all([])=True makes sense,
> isinstance(None,int) does not.

Look, even a lot of the people on this very list, who answer questions
as if they are experts, have been tripped up by all(). I am not here
to say they are stupid. I also do not mean to present myself as an
expert, whether in math, computer science, or Python in particular.
I'm just trying to present the reasoning someone (however naive) might
have to even bring up the possibility that it might make sense for
isinstance(None, foo) to be True for any foo.

I probably would not have been prompted to respond in the first place
if Steven D'Aprano hadn't deemed the notion to require three
exclamation points to shoot down. I think it is enough to say that
None is an object and it has a specific type, thus it shouldn't match
any other type; which is what he then said, albeit excitedly. ;)

John

Rhodri James

unread,
Jun 13, 2009, 5:22:14 PM6/13/09
to John Yeung, pytho...@python.org
On Sat, 13 Jun 2009 21:25:28 +0100, John Yeung
<gallium....@gmail.com> wrote:

>> > But mathematically speaking, it's intuitive that
>> > "nothing" would match any type.
>>
>> Completely wrong.  The concept you're thinking of in
>> denotational semantics is called "bottom", but bottom
>> is not a value that functions can compute and return.
>>  It is really the absence of a value.
>
> I've never heard a mathematician use the term "bottom". It certainly
> could be that I just haven't talked to the right types of
> mathematicians. I'm not sure it's even relevant. "Denotational
> semantics" is specific to computer science. My point was simply that
> even an elementary understanding of mathematics (and I'll grant a
> naive understanding of computer science as well) might lead someone to
> think that it *might* make sense for None to be the name for nothing.

Such an understanding would be clearly wrong in the context in which we
were talking (and denotational semantics is a branch of category theory,
which is not specific to computer science if you don't mind). If None
is nothing, then it can't be a string, int, float or anything else,
because they're all something.

--
Rhodri James *-* Wildebeest Herder to the Masses

John Yeung

unread,
Jun 13, 2009, 5:49:34 PM6/13/09
to
On Jun 13, 5:22 pm, "Rhodri James" <rho...@wildebst.demon.co.uk>
wrote:

> Such an understanding would be clearly wrong in the context
> in which we were talking (and denotational semantics is a
> branch of category theory, which is not specific to computer
> science if you don't mind).  If None is nothing, then it can't
> be a string, int, float or anything else, because they're all
> something.

I appreciate your explanation, and your politeness.

And I accept your answer, as well as Steven's and Paul's for that
matter. I still think it is understandable (and people may choose to
understand in a condescending way, if they wish) that someone might
not get the difference between what you are saying and the statement
that all elements of the empty set are floats. I mean, what's in the
empty set? Nothing. But you've said that floats are something. How
is it that nothing is something?

Please, I do not wish to extend this thread. My last question was
rhetorical. It's not a challenge. I accept your answer, as well as
the others. To be clear, I find it very intuitive that None does not
match the other types. But just as the devil seems to have plenty of
advocates, I guess I am a naive person's advocate, of sorts. (I must
stress I'm not the OP's advocate, nor do I consider him naive.)

John

Piet van Oostrum

unread,
Jun 13, 2009, 6:38:30 PM6/13/09
to
>>>>> Paul Rubin <http://phr...@NOSPAM.invalid> (PR) wrote:

>PR> Paul Rubin <http://phr...@NOSPAM.invalid> writes:
>>> crash, or something like that. None is a value which in Haskell has a

>PR> I got ahead of myself, of course I meant Python (the *next* sentence
>PR> was going to mention Haskell). The corresponding concept in Haskell
>PR> is called Nothing, which lives in a type functor called Maybe. I
>PR> don't have time to go into it right now but there is a notion among
>PR> language weenies these days that the presence of something like None
>PR> (in Python) or Null (in Java, SQL, etc) is a wart in a language and
>PR> that it's preferable to have something like Maybe.

The reason is that in Haskell the type system doesn't have union types.
Instead it has the disjoint sum, and Maybe is just one of them.
Otherwise you could have used the union of Nothing and any other type.
In Python there is no reason to use a disjoint sum as Python doesn't use
static typing. You can use unions of types at your hearts desire. So I
don't think there is not much difference between None and Nothing,
except for the type system.

Java, on the other hand does have static typing but does not have
disjoint sums. So they have not much choice but to put null in every
class-based type.
--
Piet van Oostrum <pi...@cs.uu.nl>
URL: http://pietvanoostrum.com [PGP 8DAE142BE17999C4]
Private email: pi...@vanoostrum.org

Steven D'Aprano

unread,
Jun 14, 2009, 9:25:20 AM6/14/09
to
John Yeung wrote:

> Paul LaFollette is probably thinking along the lines of formal logic
> or set theory. It's a little bit confused because programming isn't
> quite the same as math, and so it's a common question when designing
> and implementing programming languages how far to take certain
> abstractions. In some languages, nil, null, or none will try to
> behave as mathematically close to "nothing" (complete absence of
> anything) as possible, even though in reality they have to have some
> concrete implementation, such as perhaps being a singleton object.
> But mathematically speaking, it's intuitive that "nothing" would match
> any type.

I think you're wrong. Mathematically, you can't mix types like real numbers
and sets: while 1+0 = 1, you can't expect to get a sensible result from
1+{} or {1}∩0. (If that character between the set and zero ends up missing,
it's meant to be INTERSECTION u'\u2229'.)

Similarly, you can't add a scalar to a vector or matrix, even if one or the
other is null.


> I find that it's somewhat like the confusion that often occurs
> regarding the all() function. Some people are surprised that all([])
> returns True, but it's the same logic behind the truth of the
> statement "every element of the empty set is an integer". It's also
> true that every element of the empty set is a float. Or an elephant.

So-called "vacuous truth". It's often useful to have all([]) return true,
but it's not *always* useful -- there are reasonable cases where the
opposite behaviour would be useful:

if all(the evidence points to the Defendant's guilt) then:
the Defendant is guilty
execute(the Defendant)

sadly means that if there is no evidence that a crime has been committed,
the person accused of committing the imaginary crime will be executed.


--
Steven

Scott David Daniels

unread,
Jun 14, 2009, 10:10:11 AM6/14/09
to
Steven D'Aprano wrote:
> ... or {1}∩0. (If that character between the set and zero ends up missing,

> it's meant to be INTERSECTION u'\u2229'.)
Note that you can write this in a quite readable way in ASCII:
"it's meant to be the character u'\N{INTERSECTION}'."

--Scott David Daniels
Scott....@Acm.Org

Mel

unread,
Jun 14, 2009, 10:21:22 AM6/14/09
to
John Yeung wrote:

> And I accept your answer, as well as Steven's and Paul's for that
> matter. I still think it is understandable (and people may choose to
> understand in a condescending way, if they wish) that someone might
> not get the difference between what you are saying and the statement
> that all elements of the empty set are floats. I mean, what's in the
> empty set? Nothing. But you've said that floats are something. How
> is it that nothing is something?

It's sort of a logic equivalent of divide-by-zero.

All elements of the empty set are floats.
All elements of the empty set are ints.
Ints are not floats.
Therefore all elements of the empty set are not floats.

You elaborate your logic to talk around this problem, and you quit when you
get tired.

Mel.


Piet van Oostrum

unread,
Jun 14, 2009, 11:37:04 AM6/14/09
to
>>>>> John Yeung <gallium....@gmail.com> (JY) wrote:

>JY> I've never heard a mathematician use the term "bottom". It certainly
>JY> could be that I just haven't talked to the right types of
>JY> mathematicians.

"Bottom" is a term from lattice theory, which is a branch of mathematics.

Andre Engels

unread,
Jun 14, 2009, 11:49:42 AM6/14/09
to John Yeung, pytho...@python.org
On Sat, Jun 13, 2009 at 7:23 PM, John Yeung<gallium....@gmail.com> wrote:

> Paul LaFollette is probably thinking along the lines of formal logic
> or set theory.  It's a little bit confused because programming isn't
> quite the same as math, and so it's a common question when designing
> and implementing programming languages how far to take certain
> abstractions.  In some languages, nil, null, or none will try to
> behave as mathematically close to "nothing" (complete absence of
> anything) as possible, even though in reality they have to have some
> concrete implementation, such as perhaps being a singleton object.
> But mathematically speaking, it's intuitive that "nothing" would match
> any type.

I don't see why that would be the case. Something of the type "thingy"
is ONE thingy. Nothing is ZERO thingies, so it is not something of the
type "thingy". A car is a single car. Nothing is zero cars, which is
not a car, just like two cars is not a car.


--
André Engels, andre...@gmail.com

Paul LaFollette

unread,
Jun 14, 2009, 12:49:56 PM6/14/09
to pytho...@python.org
Thank you all for your thoughtful and useful comments. Since this has
largely morphed into a discussion of my 3rd question, perhaps it would
interest you to hear my reason for asking it.

John is just about spot on. Part of my research involves the
enumeration and generation of various combinatorial objects using what
are called "loopless" or "constant time" algorithms. (This means that
the time required to move from one object to the next is bounded by a
constant that is independent of the size of the object. It is related
to following idea: If I generate all of the possible patterns
expressible with N bits by simply counting in binary, as many as N
bits may change from one pattern to the next. On the other hand if I
use Gray code only one bit changes from each pattern to the next. If
you are interested in this essentially useless (but fun) subject, the
seminal paper by Gideon Ehrlich is here:
http://portal.acm.org/citation.cfm?id=321781 )

Now, suppose that I want to generate, say, the set of all ordered
trees with N nodes. I need to be able to represent the empty ordered
tree, i.e. the tree with with zero nodes. There are a lot of ways I
could do this. The problem is that I might tomorrow be looking
instead at rooted trees, or free trees, or Young tableaux and in each
case I will need to represent the empty rooted tree, or the empty free
tree, or the empty Young tableau.

In a very real sense, the empty Young tableau IS a Young tableau and
the empty ordered tree IS an ordered tree. But in an equally real
sense they are the same "ghost of a thing" looked at in different
universes of discourse.

So, what I would like is some sort of object that is a "kind of"
everything but contains nothing, a unique minimal element of the
partial ordering imposed on the set of classes by the inheritance
heierarchy. Whilst I am not naive mathematically, I am relatively
naive in the area of language design. In my naivete, it seemed to me
that None could have been designed to be such a thing. Apparently
that is incorrect.

The matter is not urgent, there are oodles of workarounds. Indeed,
having once found a particular loopless algorithm I don't necessarily
publish an implementation of it, but rather a formal description and
proof of correctness. Still, before I submit things for publication I
generally prefer to implement them for myself just to convince myself
that what I have proved correct in fact works at least for modest
values of N.

Paul
____________________________________
paul[dot]lafollette[at]gmail.com
http://www.cis.temple.edu/~lafollet

Arnaud Delobelle

unread,
Jun 14, 2009, 1:02:54 PM6/14/09
to
Steven D'Aprano <st...@REMOVETHIS.cybersource.com.au> writes:
> So-called "vacuous truth". It's often useful to have all([]) return true,
> but it's not *always* useful -- there are reasonable cases where the
> opposite behaviour would be useful:
>
> if all(the evidence points to the Defendant's guilt) then:
> the Defendant is guilty
> execute(the Defendant)
>
> sadly means that if there is no evidence that a crime has been committed,
> the person accused of committing the imaginary crime will be executed.

This is a bad example. Someone is not convicted of a crime just because
all the available evidence points towards their guilt. There may be
very little evidence altogether, or it might just be circumstancial, or
unconvincing. Even though it may all point towards the defendent's
guilt, it doesn't mean they will be convicted. There needs to be enough
evidence to convince the jury. So it would be something like:

if sum(guilt_weight(e) for e in evidence) > GUILT_THRESHOLD:
the defendant is guilty
...

--
Arnaud

Andre Engels

unread,
Jun 14, 2009, 1:26:31 PM6/14/09
to Paul LaFollette, pytho...@python.org
On Sun, Jun 14, 2009 at 6:49 PM, Paul
LaFollette<paul.la...@gmail.com> wrote:
> Now, suppose that I want to generate, say, the set of all ordered
> trees with N nodes.   I need to be able to represent the empty ordered
> tree, i.e. the tree with with zero nodes.  There are a lot of ways I
> could do this.  The problem is that I might tomorrow be looking
> instead at rooted trees, or free trees, or Young tableaux and in each
> case I will need to represent the empty rooted tree, or the empty free
> tree, or the empty Young tableau.
>
> In a very real sense, the empty Young tableau IS a Young tableau and
> the empty ordered tree IS an ordered tree.  But in an equally real
> sense they are the same "ghost of a thing" looked at in different
> universes of discourse.

But do you also want the empty Young tableau to BE an ordered tree? A
number? A diddlewoodaddy? It seems much more logical to me to define
your Young tableaus such that the definition includes the empty one as
well.


--
André Engels, andre...@gmail.com

MRAB

unread,
Jun 14, 2009, 2:00:26 PM6/14/09
to pytho...@python.org
For strings there's the empty string with the same methods. It's not the
same as None.

For lists there's the empty list with the same methods. It's not the
same as None.

For dicts there's the empty dict with the same methods. It's not the
same as None.

For sets there's the empty set with the same methods. It's not the same
as None.

etc.

Aaron Brady

unread,
Jun 14, 2009, 2:32:35 PM6/14/09
to
On Jun 14, 10:02 am, Arnaud Delobelle <arno...@googlemail.com> wrote:
snip

> guilt, it doesn't mean they will be convicted.  There needs to be enough
> evidence to convince the jury.  So it would be something like:
>
> if sum(guilt_weight(e) for e in evidence) > GUILT_THRESHOLD:
>    the defendant is guilty
>    ...
>
> --
> Arnaud

You all are only two months late.

http://groups.google.com/group/comp.lang.python/msg/7b63d0d11246ecad

Can't argue with results.

Paul Rubin

unread,
Jun 14, 2009, 3:37:34 PM6/14/09
to
Andre Engels <andre...@gmail.com> writes:
> I don't see why that would be the case. Something of the type "thingy"
> is ONE thingy. Nothing is ZERO thingies, so it is not something of the
> type "thingy". A car is a single car. Nothing is zero cars, which is
> not a car, just like two cars is not a car.

That seems to confuse values with collections of them. A car is not
the same as a one-element list of cars. Nothing is not the same as a
zero-element list of cars.

Andre Engels

unread,
Jun 14, 2009, 4:11:18 PM6/14/09
to pytho...@python.org

So you are of the opinion that "nothing" _is_ a car?

--
André Engels, andre...@gmail.com

Paul Rubin

unread,
Jun 14, 2009, 4:21:14 PM6/14/09
to
Andre Engels <andre...@gmail.com> writes:
> > That seems to confuse values with collections of them.  A car is not
> > the same as a one-element list of cars.  Nothing is not the same as a
> > zero-element list of cars.
>
> So you are of the opinion that "nothing" _is_ a car?

Eh? No of course not. a != b and b != c does not mean a==c.
I don't understand what you're getting at.

Andre Engels

unread,
Jun 14, 2009, 4:30:32 PM6/14/09
to pytho...@python.org
On Sun, Jun 14, 2009 at 10:21 PM, Paul
Rubin<http://phr...@nospam.invalid> wrote:
> Andre Engels <andre...@gmail.com> writes:
>> > That seems to confuse values with collections of them.  A car is not
>> > the same as a one-element list of cars.  Nothing is not the same as a

>> > zero-element list of cars.
>>
>> So you are of the opinion that "nothing" _is_ a car?
>
> Eh?  No of course not.  a != b and b != c does not mean a==c.
> I don't understand what you're getting at.

I was making a point that I don't agree that "nothing" would match any
type. The reason was that anything of the type car is one car, not two
cars or zero cars, but "nothing" is zero cars. You don't agree with
me, so apparently you are of the opinion that "nothing" would be a

Paul Rubin

unread,
Jun 14, 2009, 5:19:37 PM6/14/09
to
Andre Engels <andre...@gmail.com> writes:
> I was making a point that I don't agree that "nothing" would match any
> type. The reason was that anything of the type car is one car, not two
> cars or zero cars, but "nothing" is zero cars. You don't agree with
> me, so apparently you are of the opinion that "nothing" would be a car.

I don't agree that "nothing" is "zero cars". Just like I don't agree
that the empty set, the empty list, and the empty string are the same
thing.

Terry Reedy

unread,
Jun 14, 2009, 7:14:10 PM6/14/09
to pytho...@python.org
Steven D'Aprano wrote:
>
> So-called "vacuous truth". It's often useful to have all([]) return
> true, but it's not *always* useful -- there are reasonable cases
> where the opposite behaviour would be useful:
>
> if all(the evidence points to the Defendant's guilt) then: the
> Defendant is guilty execute(the Defendant)
>
> sadly means that if there is no evidence that a crime has been
> committed, the person accused of committing the imaginary crime will
> be executed.

It seems to me that the absurd conclusion implied by the theorem
invalidates the theorem rather than supporting your point. No evidence
is only the endpoint of a continuum. Suppose that 'all' is one teensy
weensy bit of evidence. A drunked bystander gives a vague description
that fits. Or twenty years before, the defendent argued with the
deceased and said 'I wish you were dead'. Should the person be executed?
I say not. You?

Of course, a person would only be a defendant in the absence of evidence
under a depraved regime that would not much care if there were.

Try finding another 'reasonable case'.

Terry Jan Reedy


Terry Reedy

unread,
Jun 14, 2009, 7:27:46 PM6/14/09
to pytho...@python.org
Mel wrote:
> John Yeung wrote:
>
>> And I accept your answer, as well as Steven's and Paul's for that
>> matter. I still think it is understandable (and people may choose to
>> understand in a condescending way, if they wish) that someone might
>> not get the difference between what you are saying and the statement
>> that all elements of the empty set are floats. I mean, what's in the
>> empty set? Nothing. But you've said that floats are something. How
>> is it that nothing is something?
>
> It's sort of a logic equivalent of divide-by-zero.
>
> All elements of the empty set are floats.
> All elements of the empty set are ints.
> Ints are not floats.
> Therefore all elements of the empty set are not floats.
If
x in e => x in floats
x in e => x in ints
x in ints => x not in floats
Then
x in e => x not in floats, a contradition,
So
not(x in e), the definition of empty set.

> You elaborate your logic to talk around this problem, and you quit when you
> get tired.

No problem. Colloquial English is not the same as careful logic.
2 minutes, tired? Nah.

tjr

Terry Reedy

unread,
Jun 14, 2009, 7:36:11 PM6/14/09
to pytho...@python.org
Paul LaFollette wrote:
> Thank you all for your thoughtful and useful comments. Since this has
> largely morphed into a discussion of my 3rd question, perhaps it would
> interest you to hear my reason for asking it.
>
> John is just about spot on. Part of my research involves the
> enumeration and generation of various combinatorial objects using what
> are called "loopless" or "constant time" algorithms. (This means that
> the time required to move from one object to the next is bounded by a
> constant that is independent of the size of the object. It is related
> to following idea: If I generate all of the possible patterns
> expressible with N bits by simply counting in binary, as many as N
> bits may change from one pattern to the next. On the other hand if I
> use Gray code only one bit changes from each pattern to the next.

But the number of bits you must examine to determine which to change is
bounded by N and increases with N.

Aaron Brady

unread,
Jun 14, 2009, 9:26:55 PM6/14/09
to
On Jun 14, 12:37 pm, Paul Rubin <http://phr...@NOSPAM.invalid> wrote:
> Andre Engels <andreeng...@gmail.com> writes:
snip

> > type "thingy". A car is a single car. Nothing is zero cars, which is
> > not a car, just like two cars is not a car.
>
> That seems to confuse values with collections of them.  A car is not
> the same as a one-element list of cars.  Nothing is not the same as a
> zero-element list of cars.

Collections are a mathematical (ideal, cognitive) construct.

Steven D'Aprano

unread,
Jun 15, 2009, 12:27:18 AM6/15/09
to

Not all trials are jury trials, and not all cultures have a presumption
of innocence.

There are, in fact, many places where the government and police think
little of falsifying evidence to convict innocent people, including
people that they know are innocent of any crime (an extreme case was
Stalin's show trials). But as far as I know, nobody ever argues that
people are guilty based on the principle of Vacuous Truth: everybody
agrees that if there is no evidence of a crime, the person should be
considered innocent rather than guilty. Even Stalin manufactured evidence
of crimes. (In most cases, that evidence was to torture people into
confessing to crimes that did not, in fact, take place.)

To put it another way, logically:

all(the evidence is true)
not any(the evidence is false)

should be considered identical, but in practice, we treat:

evidence = [] # evidence of a crime
all(evidence)

as false instead of true, even in places with no presumption of innocence.

While:

not any(map(operator.not_, evidence))

is also treated as false.


In any case, I'm not arguing against vacuous truth -- it's clearly the
right way to deal with empty sets *nearly always*. But it isn't entirely
straight-forward, and leads to some difficulties, such as a vacuous truth
X implies both Y and not Y at the same time.


--
Steven

Steven D'Aprano

unread,
Jun 15, 2009, 12:50:27 AM6/15/09
to
On Sun, 14 Jun 2009 19:14:10 -0400, Terry Reedy wrote:

> Steven D'Aprano wrote:
>>
>> So-called "vacuous truth". It's often useful to have all([]) return
>> true, but it's not *always* useful -- there are reasonable cases where
>> the opposite behaviour would be useful:

[...]


> It seems to me that the absurd conclusion implied by the theorem
> invalidates the theorem rather than supporting your point.

I wouldn't go so far as to say the vacuous truth theorem ("empty
statements are true") is invalidated. The Wikipedia article discusses
various reasons why it's more correct (or at least more useful) to treat
vacuous statements as true:

http://en.wikipedia.org/wiki/Vacuous_truth

But it's not without difficulties -- however those difficulties are
smaller than those if you take vacuous statements as false in general.

[...]


> Try finding another 'reasonable case'.

Any time you do something like:

if not x and all(x):
process(x)


instead of just:

if all(x):
process(x)


I can't think of a real world example off the top of my head, but here's
a contrived example demonstrating that vacuous truths imply both a fact
and it's opposite:


def startswith(s, chars):
"""Return True if s starts with any of chars."""
for c in chars:
if s.startswith(c): return True
return False


if all([startswith(w, "aeiou") for w in words]):
print "All the words start with vowels."

if all([startswith(w, "bcdfghjklmnpqrstvwxyz") for w in words]):
print "All of the words start with consonants."


If words is empty, this code claims that all of the words start with
vowels as well as starting with consonants.

There are, of course, ways to work around that other than rejecting
vacuous truths. One is to simply use an "elif" for the second test.

--
Steven

Aaron Brady

unread,
Jun 15, 2009, 12:10:56 PM6/15/09
to
On Jun 14, 9:50 pm, Steven D'Aprano

<ste...@REMOVE.THIS.cybersource.com.au> wrote:
> On Sun, 14 Jun 2009 19:14:10 -0400, Terry Reedy wrote:
> > Steven D'Aprano wrote:
>
> >> So-called "vacuous truth". It's often useful to have all([]) return
> >> true, but it's not *always* useful -- there are reasonable cases where
> >> the opposite behaviour would be useful:
> [...]
> > It seems to me that the absurd conclusion implied by the theorem
> > invalidates the theorem rather than supporting your point.
>
> I wouldn't go so far as to say the vacuous truth theorem ("empty
> statements are true") is invalidated. The Wikipedia article discusses
> various reasons why it's more correct (or at least more useful) to treat
> vacuous statements as true:
>
> http://en.wikipedia.org/wiki/Vacuous_truth
>
> But it's not without difficulties -- however those difficulties are
> smaller than those if you take vacuous statements as false in general.
snip

Those difficulties are pretty gaping.

I would start by dividing the natural language 'use cases' of 'if'
statements into imperative and declarative.

Declarative:

If it's raining, it's cloudy.

In this case, the assertion is meant to convey a general, non-
concrete, observation trend across space and time. Its content is a
claim of 100% correlation between two statuses of the real world.

Imperative:

If you're out of bread, go buy some.

Here, the speaker is in a position of authority over the audience, who
will be following his/er commands, and acting under the speaker's
authority. The speaker is meaning to convey conditional instructions,
for a possible circumstance. There is no component of observation or
assertion.

We see this distinction in programming too. Is the user merely
asserting a relation, or defining a procedure?

Implies( Raining( x ), Cloudy( x ) )

or

if OutOfBread( x ):
BuyBread( )

The 'if' statement is counterfactual in its native environment. As
such, natural speakers never use it in vacuous cases, and it's not
naturally defined.

In a mathematical (ideal) environment, its semantics are artificially
constructed like any other math predicate, and proofs involving it
will define its vacuous case, or fail.

Terry Reedy

unread,
Jun 15, 2009, 4:00:42 PM6/15/09
to pytho...@python.org

So? These are true and non-contradictory. They are NOT 'opposites'.
Together they imply that there are are no words in words, which is true.
To paraphrase my response to mel, I believe it was:

[(x in words => x.startswith(vowel)) and
(x in words => x.startswith(nonvowel)) and
x.startswith(vowel) <=> not(x.startswith(nonvowel)]
=> not(x in words)
which is the definition of 'words is the empty set'
by the law of contradiction.

The negation of 'all words starts with vowel' is 'there exists a word
that starts with a non-vowel', which is different from 'all words start
with consonants' since the latter is true when there are no words
whereas the former is not.

Terry Jan Reedy

Bruno Desthuilliers

unread,
Jun 17, 2009, 6:47:24 AM6/17/09
to
John Yeung a �crit :
> On Jun 13, 2:29 am, Steven D'Aprano
> <st...@REMOVETHIS.cybersource.com.au> wrote:
>> Paul LaFollette wrote:
>>> 3) (this is purely philosophical but I am curious)
>>> Would it not be more intuitive if
>>> isinstance(None, <anything at all>) returned true?
>> Good grief no!!!
>>
>> None is an object. It has a type, NoneType. It's *not* a
>> string, or a float, or an int, or a list, so why would
>> you want isinstance() to *lie* and say that it is?
>
> Because you might want None to behave as though it were nothing at
> all.

>
> Paul LaFollette is probably thinking along the lines of formal logic
> or set theory. It's a little bit confused because programming isn't
> quite the same as math, and so it's a common question when designing
> and implementing programming languages how far to take certain
> abstractions. In some languages, nil, null, or none will try to
> behave as mathematically close to "nothing" (complete absence of
> anything) as possible, even though in reality they have to have some
> concrete implementation, such as perhaps being a singleton object.
> But mathematically speaking, it's intuitive that "nothing" would match
> any type.

IOW, what's the OP is after is not the None type, but some yet
unexisting "Anything" type !-)

Aaron Brady

unread,
Jun 17, 2009, 11:10:48 AM6/17/09
to
On Jun 17, 5:47 am, Bruno Desthuilliers <bruno.
42.desthuilli...@websiteburo.invalid> wrote:
> John Yeung a écrit :

> > But mathematically speaking, it's intuitive that "nothing" would match
> > any type.
>
> IOW, what's the OP is after is not the None type, but some yet
> unexisting "Anything" type !-)

The behaviors of the 'anything' object are a subset of those of any
other object.

I don't believe that 'subset' is a proper characterization of the
relationship between the methods of a subclass and the methods of its
superclass. But 'superset' may be.

Should 'object' inherit from None?

Paul Rubin

unread,
Jun 20, 2009, 5:38:00 AM6/20/09
to
Paul LaFollette <paul.la...@gmail.com> writes:
> So, what I would like is some sort of object that is a "kind of"
> everything but contains nothing, a unique minimal element of the
> partial ordering imposed on the set of classes by the inheritance
> heierarchy. Whilst I am not naive mathematically, I am relatively
> naive in the area of language design. In my naivete, it seemed to me
> that None could have been designed to be such a thing. Apparently
> that is incorrect.

I don't remember if I linked to this article:

http://en.wikibooks.org/wiki/Haskell/Denotational_semantics

You might like it. If you want to learn some contemporary programming
language theory at a mathematical level, start with Harper's
"Practical Foundations for Programming Languages":

http://www.cs.cmu.edu/~rwh/plbook/book.pdf

0 new messages