Skip to content

Instantly share code, notes, and snippets.

@sheavalentine
Last active May 11, 2016 01:59
Show Gist options
  • Save sheavalentine/d829ad091149a1463a3b to your computer and use it in GitHub Desktop.
Save sheavalentine/d829ad091149a1463a3b to your computer and use it in GitHub Desktop.
The magic of maybe

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.

@sobelk
Copy link

sobelk commented May 22, 2015

I like it. Let's try it out!

@youcandanch
Copy link

Dig it.

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