Credit: Dinu C. Gherman
The usual marker for “there’s
nothing here” is
None, but we may
be able to do better than that:
class Null: """ Null objects always and reliably "do nothing." """ def _ _init_ _(self, *args, **kwargs): pass def _ _call_ _(self, *args, **kwargs): return self def _ _repr_ _(self): return "Null( )" def _ _nonzero_ _(self): return 0 def _ _getattr_ _(self, name): return self def _ _setattr_ _(self, name, value): return self def _ _delattr_ _(self, name): return self
An instance of the
Null class can replace the
None. Using this class, you can
avoid many conditional statements in your code and can often express
algorithms with little or no checking for special values. This recipe
is a sample implementation of the Null Object design pattern (see
“The Null Object Pattern”, B.
Woolf, Pattern Languages of Programming, PLoP
96, September 1996).
Null class ignores
all parameters passed when constructing or calling instances and any
attempt to set or delete attributes. Any call or attempt to access an
attribute (or a method, since Python does not distinguish between the
two and calls
_ _getattr_ _ either way) returns
Null instance (i.e.,
self, since there’s no reason to
create a new one). For example, if you have a computation such as:
def compute(x, y): try: "lots of computation here to return some appropriate object" except SomeError: return None
and you use it like this:
for x in xs: for y in ys: obj = compute(x, y) if obj is not None: obj.somemethod(y, x)
you can usefully change the computation to:
def compute(x, y): try: "lots of computation here to return some appropriate object" except SomeError: return Null( )
and thus simplify it as:
for x in xs: for y in ys: compute(x, y).somemethod(y, x)
Thus, you don’t need to check whether
compute has returned a real result or an instance
Null. Even in the latter case, you can safely
and innocuously call on it whatever method you want.
_ _getattr_ _ for special methods as
well. This means that you may have to take some care and customize
Null to your application’s needs,
either directly in the class’s sources or by
subclassing it appropriately. For example, with this
Null, any comparison
Null instances, even
a==a, returns a
and evaluates as false. (Note that we’ve had to
_ _nonzero_ _ for this purpose,
_ _nonzero_ _ must return an
int.) If this is a problem for your purposes, you
_ _eq_ _ (in
itself or in an appropriate subclass) and implement it appropriately.
Similar delicate considerations apply to several other special
The goal of
Null objects is to provide an
intelligent replacement for the often-used primitive value
None in Python (
Null or null
pointers in other languages). These “nobody lives
here” markers are used for many purposes, including
the important case in which one member of a group of otherwise
similar elements is special. Usually, this usage results in
conditional statements to distinguish between ordinary elements and
the primitive null (e.g.,
None) value, but
Null objects help you avoid that.
Among the advantages of using
Null objects are the
Superfluous conditional statements can be avoided by providing a
first-class object alternative for the primitive value
None, thereby improving code readability.
They can act as a placeholder for objects whose behavior is not yet implemented.
They can be used polymorphically with instances of any other class.
They are very predictable.
To cope with the disadvantage of creating large numbers of passive objects that do nothing but occupy memory space, the Null Object pattern is often combined with the Singleton pattern (see Recipe 5.22), but this recipe does not explore that combination.
“The Null Object Pattern”, B. Woolf, Pattern Languages of Programming, PLoP 96, September 1996, http://www.cs.wustl.edu/~schmidt/PLoP-96/woolf1.ps.gz.