Skip to content

Instantly share code, notes, and snippets.

@codenameyau
Forked from sheavalentine/gist:d829ad091149a1463a3b
Last active August 29, 2015 14:23
Show Gist options
  • Save codenameyau/c8438b30971453d32ea6 to your computer and use it in GitHub Desktop.
Save codenameyau/c8438b30971453d32ea6 to your computer and use it in GitHub Desktop.

The Magic of Maybe

The Pattern

Consider the following code

def do_some_stuff(x)
  try:
    val = f(x)
  except NameError, e:
    val = False
  return va;

Now of course if that happens once or twice in a piece of code it's not a big deal. However in a large project this can happen over and over again.

Then you have another issue. Consider the common Django pattern:

try:
   x = SomeModel.objects.get(foo=bar)
except SomeModel.DoesNotExist:
   x = g(bar)

This ends up showing up over and over again in any sufficiently large Django app.

There is a better way.

One of the beauties of Python is that is very usable for functional patterns fure to the first class nature of functions. This means we ca get rid of all of this boilerplate by pulling an idiom from functional languages - specifically maybe. Don't worry, I'm not going full on monad on you here, just a simple function to handle this elegantly.

def maybe(f, default = None, exceptions = (Exception,) ):
    def _maybe(*args, **kwargs):
        try:
            return f(*args, **kwargs)
        except exceptions:
            if callable(default):
                return default(*args, **kwargs)
            else:
                return default
    return _maybe
    
#as a decorator
def perhaps(default = None, exceptions = (Exception,)):
    def wraps(f):
        return maybe(f,default,exceptions)
    return wraps

Now, let's look against at our two use cases:

def do_some_stuff(x)
  try:
    val = f(x)
  except NameError, e:
    val = False
  return val

becomes

@perhaps(False, NameError)
def do_some_stuff(x): f(x)

and

try:
   x = SomeModel.objects.get(foo=bar)
except SomeModel.DoesNotExist, KeyError:
   x = g(foo=bar)

becomes

  f = maybe(SomeModel.objects.get, g, (SomeModel.DoesNotExist, KeyError))
  x = f(foo=bar)

Remember, with great power comes great responsibility.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment