accessing an object instance by only having one of its attribute values

Paul McGuire ptmcg at austin.rr.com
Mon Jul 9 09:54:45 EDT 2007


On Jul 8, 8:29 pm, mshiltonj <mshilt... at gmail.com> wrote:
>
> Not sure why I slipped into the habit of testing for None, though. :-(
>

There is nothing wrong with testing for None.  But the right ways to
test for None are:
  if x is None:
and
  if x is not None:

Since None is a singleton, it is a waste to test using == or !=.  The
identity tests 'is' and 'is not' are sufficient.

In fact, testing for None is a very common way to implement a default
argument for an instance method (usually __init__ of a class) in which
the default is a list (usually an empty list, but not always).

The WRONG way:

class BorkBorkBork(object):
    def __init__(self,words=[]):
        self.vocabulary = words

Since the argument "words=[]" gets evaluated at class definition time,
all instances of BorkBorkBork will end up using the same list, which
is almost never the desired behavior, and a common surprise for new
Pythoners.

The ALMOST RIGHT way:

class BorkBorkBork(object):
    def __init__(self,words=None):
        if words:
            self.vocabulary = words
        else:
            self.vocabulary = []

This is ALMOST RIGHT, now the default value of words is None, and the
if test fails.  Unfortunately, if this were called using:

chef = BorkBorkBork([])

then the if test fails, not because the argument was omitted from the
constructor, but BECAUSE THE PASSED VALUE EVALUATES TO FALSE!  "So
what?" you say, since in the else branch we just set the default value
to an empty list anyway.  But what about this?

Why the ALMOST RIGHT way isn't ALWAYS RIGHT:

class BorkBorkBork(object):
    def __init__(self,words=None):
        if words:
            self.vocabulary = words
        else:
            self.vocabulary = ['bork','hernie','fernie','bernie']

Our default starting vocabulary isn't empty now, but there is no way
to initialize a BorkBorkBork'er to an empty list.

The RIGHT way:

class BorkBorkBork(object):
    def __init__(self,words=None):
        if words is not None:
            self.vocabulary = words
        else:
            self.vocabulary = ['bork','hernie','fernie','bernie']


Now the loophole is closed.  If we want to initialize to an empty
list, we can do so; or if we omit the argument, then the newly-
constructed BorkBorkBork instance will have a minimally functional
vocabulary.

So testing for None is not inherently bad, and in many cases a healthy
idiom.

-- Paul




More information about the Python-list mailing list