PEP 285: Adding a bool type

Bernhard Herzog bh at intevation.de
Sun Apr 7 16:36:55 EDT 2002


Jeff Shannon <jeff at ccvcorp.com> writes:

> In article <3CAE1CC8.7D18F4A9 at alcyone.com>, max at alcyone.com 
> says...
> > Comparing to None (preferably via is rather than ==, since == can be
> > overridden to do strange things) is perfectly legitimate when an API
> > declares that a function or method returns "an object or None."  After
> > all, the __nonzero__ method can be overridden to make perfectly valid
> > objects evaluate to false in a truth test.
> 
> I would suspect that anyone defining such an object would be 
> rather surprised if you refused to test it with 'if not object:' 

To illustrate the point Erik made, here's how I learned to compare to
None as explicitly as possible and not just testing whether a certain
object is true.

Consider a class like this:

class Xyzzy:

    def __init__(self, parent = None):
        """Instances of Xyzzy may have an optional parent"""
        if parent:
            # if we're instantiated with a parent add
            # ourselves to its list of children.
            parent.add_child(self)


The parents of the Xyzzy isntances defined some protocol for managing
children and the children always called a certain method of the parent
when you instantiated them with a parent.

At first, those parents were always true so that that if statement
always worked correctly, i.e. called the parent's add_child method if
and only if Xyzzy was instantiated with a parent.

Later, the parents were extended to support the sequence protocol, so
that you could use len(parent) to find out how many children there were,
for isntance. Unfortunately, that meant that suddenly all (potential)
parents that didn't have children yet were false! After all, an object
that doesn't implement __nonzero__ (which didn't yet exist in the python
version I was using back then IIRC) but implements __len__ is considered
false if __len__ returns 0.

The solution was to switch to an explicit test for None.

And testing for None with "is" is a good idea. Not only can any object
be equal to None if it implements the various __*__ methods related to
comparison accordingly, "is" is also faster. And when the objects you
compare to None implements __getattr__ but not __eq__ or __cmp__
comparing for equality can be quite slow because Python tries to get
hold of several "magic" methods before it reverts to testing for
identity anyway:

>>> class C:
...     def __getattr__(self, attr):
...             print "__getattr__", attr
...             raise AttributeError, attr
... 
>>> c = C()
>>> c == None
__getattr__ __eq__
__getattr__ __coerce__
__getattr__ __cmp__
0
>>> if c: pass
... 
__getattr__ __nonzero__
__getattr__ __len__
>>> 


Whether the speed matters depends on your particular application, of
course.


   Bernhard

-- 
Intevation GmbH                                 http://intevation.de/
Sketch                                 http://sketch.sourceforge.net/
MapIt!                                           http://www.mapit.de/



More information about the Python-list mailing list