Permanent objects?

Erik Max Francis max at alcyone.com
Thu Dec 26 04:16:46 EST 2002


Cliff Wells wrote:

> But then isn't this sort of like the case where a function tests the
> type of object being passed to it (i.e. type(s) == type(""))?  There
> have been arguments on this list in the past that it's bad to
> explicitly
> test for a particular type, so wouldn't this fall in the same
> category?
> That is, if an object mimics a particular type, and can be used in
> place
> of that type, why should a function exclude it if it isn't that type?

That's definitely true (most of the time, anyway) for the case of
explicit type tests.  In a dynamic language like Python, it really
doesn't matter if the object has a certain type, it just matters that it
has the right interface.

Tests against None are genuinely different, however.  None is usually
used to indicate the lack of another meaningful object.  In other words,
None is a _unique_ object that says, "There's no object here."  In other
words, None is used as a sentinel object to represent something special,
distinct from all other objects.  There's exactly one None, and it's
different from everything else.

In that context, where it's appropriate to use None in the first place,
you don't want to test whether it's _equal_ to None, you want to test
whether it _is_ the None object.  Since the goal here is to use None as
a sentinel object to indicate something special, testing for None-ness
with equality (not identity) can actually be counterproductive, because
it means that someone can lie to you.  Again, it is really something of
a perverse case where an instance is implemented such that
__eq__/__cmp__ are overridden to test equal to None.  But this really is
a case where you want to know if it's _that_ object or something else.

That's why when you hear talk about where people want to have optional
arguments that could _also be None_, they talk about making _another_
unique sentinel object, usually a private one to the class:

	class C:
	    _sentinel = object() # or whatever gets you a unique object
	    def f(self, some, other=_sentinel):
	        if other is _sentinel:
	            ... # handle the case where other wasn't specified
	        ... # handle the normal case, but None is a valid value

The test with is (not ==) is important here, because I want to make sure
it's _that object_, not merely an object that tests equal to it.  In
fact you _don't_ want someone pretending

> For instance, if a function expects a file, but is passed a file-like
> object, it shouldn't reject that object just because it isn't a real
> file, doing so only limits the usefulness of the function.  It seems
> that by that argument, x == None would be preferable to x is None.

I agree that at first glance it does look like an analogous situation. 
But the difference here is that when you're testing for None vs.
not-None, you're really using the None value as a sentinel.  When you
want to know whether something implements a certain interface (say, a
file interface in your example), the best way to do it is to simply try
to use it and see if it works (granted, there are exceptions).  Here
what we're doing is not trying to tell if something matches a pattern,
we're trying to test if we got _anything at all_.  To do that we need to
have a special and unique sentinel object to represent "Whoops, no
object here," and that sentinel is (usually) None.

Again, this is something of an edge case, since it really would be
something of a perversion (in my opinion) to create an instance that
tests equal to (==) None.  A greater perversion, as I pointed out
earlier -- and one that can't be avoided here -- would be rebinding the
name None itself.

I think testing None-ness with the is operator rather than the ==
operator is really a better idiom, although if everyone's playing by the
rules in practice it probably wouldn't matter.  I personally use the is
operator exclusively, because it also sends a message to anyone reading
the code:  I mean _the_ None, some "some" None.

-- 
 Erik Max Francis / max at alcyone.com / http://www.alcyone.com/max/
 __ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE
/  \ Who needs a dream / Who needs ambition
\__/ The Russian, _Chess_
    Bosskey.net: Aliens vs. Predator 2 / http://www.bosskey.net/avp2/
 A personal guide to Aliens vs. Predator 2.



More information about the Python-list mailing list