Skip to content

Instantly share code, notes, and snippets.

@dfischer
Forked from kernc/null.py
Created March 10, 2021 17:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dfischer/2f07e3d35e8750767384e018b23e5e10 to your computer and use it in GitHub Desktop.
Save dfischer/2f07e3d35e8750767384e018b23e5e10 to your computer and use it in GitHub Desktop.
Null object pattern (Python)
"""
This module provides the Null class for the null object design pattern.
"""
from collections import MutableMapping, MutableSequence
class _MetaNull(type): pass
class Null(type):
"""Null object design pattern.
This class traps and ignores everything. Instances of it always and
reliably do nothing, or return 0, '', False, or other logical,
contextually-appropriate emptiness or negation.
>>> Null()(1, kwarg=2)()[3]['4'] is Null
True
>>> Null.method().attr is Null
True
>>> Null * 1 / 2 + 3 == Null
<Null>
>>> bool(Null), str(Null), repr(Null), int(Null), len(Null)
(False, '', '<Null>', 0, 0)
>>> [i for i in Null]
[]
Roughly, the goal with Null objects is to provide an 'intelligent'
replacement for the often used primitive data type None in Python
or Null (or Null pointers) in other languages. These are used for
many purposes including the important case where one member of some
group of otherwise similar elements is special for whatever reason.
Most often this results in conditional statements to distinguish
between ordinary elements and the primitive Null value.
Among the advantages of using Null objects are the following:
* Superfluous conditional statements can be avoided
by providing a first class object alternative for
the primitive value None.
* Code readability is improved.
* Null objects can act as a placeholder for objects
with behaviour that is not yet implemented.
* Null objects can be replaced for any other class.
* Null objects are very predictable at what they do.
To cope with the disadvantage of creating large numbers of passive
objects that do nothing but occupy memory space Null objects are
often combined with the Singleton pattern.
For more information use any internet search engine and look for
combinations of these words: Null, object, design and pattern.
Dinu C. Gherman,
August 2001
"""
__metaclass__ = _MetaNull
__hash__ = type.__hash__
__slots__ = ()
def __next__(_): raise StopIteration
next = __next__ # Python 2 compatibility
__dir__ = lambda _: []
__str__ = lambda _: ''
__repr__ = lambda _: '<Null>'
__bytes__ = lambda _: b''
__int__ = \
__len__ = \
__index__ = \
__round__ = \
__complex__ = lambda *_: 0
__float__ = lambda *_: 0.
__eq__ = \
__ge__ = \
__gt__ = \
__le__ = \
__lt__ = \
__ne__ = \
__or__ = \
__and__ = \
__del__ = \
__get__ = \
__set__ = \
__abs__ = \
__add__ = \
__mod__ = \
__mul__ = \
__new__ = \
__neg__ = \
__pos__ = \
__pow__ = \
__ror__ = \
__sub__ = \
__xor__ = \
__call__ = \
__exit__ = \
__init__ = \
__iter__ = \
__radd__ = \
__rand__ = \
__rmod__ = \
__rmul__ = \
__rpow__ = \
__rsub__ = \
__rxor__ = \
__enter__ = \
__delete__ = \
__divmod__ = \
__invert__ = \
__lshift__ = \
__rshift__ = \
__delattr__ = \
__delitem__ = \
__getattr__ = \
__getitem__ = \
__rdivmod__ = \
__rlshift__ = \
__rrshift__ = \
__setattr__ = \
__setitem__ = \
__truediv__ = \
__floordiv__ = \
__rtruediv__ = \
__rfloordiv__ = \
__getattribute__ = lambda self, *_, **__: self
Null.__class__ = Null
class nulldict(dict):
def __missing__(self, key):
return Null
class nulllist(list):
def __getitem__(self, i):
return list.__getitem__(self, i) if i < len(self) else Null
class nulltuple(tuple):
def __getitem__(self, i):
return tuple.__getitem__(self, i) if i < len(self) else Null
def nullify(obj):
if isinstance(obj, MutableMapping):
return nulldict(obj)
if isinstance(obj, tuple):
return nulltuple(obj)
if isinstance(obj, MutableSequence):
return nulllist(obj):
return obj or Null
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment