Python: try-except as an Expression?

Here's a context manager that provides a little bit of a shortcut:

from contextlib import contextmanager

@contextmanager
def catch(*exceptions, **kwargs):
    try:
        yield kwargs.get("default", None)
    except exceptions or Exception:
        pass

Usage:

with catch(ZeroDivisionError, default=0) as x:
    x = 3 / 0              # error

print x                    # prints 0, the default

The basic idea here is that the context manager returns whatever default value you pass it, which is then assigned to the variable you specified in the with statement's as clause. Then, inside the context, you execute a statement that tries to assign to that same variable. If it raises an exception, the context manager catches and silently ignores it, but since the assignment didn't happen, the default value remains.

Might be particularly useful for multi-line calculations that nevertheless result in a single value.


Since agf already provided the approach I'd recommend, here's a version of his routine with a couple of minor enhancements:

def try_except(success, failure, *exceptions):
    try:
        return success()
    except exceptions or Exception:
        return failure() if callable(failure) else failure

This version:

  1. Lets you specify exactly which exceptions will be caught as additional optional arguments. You should always catch the minimum set of exceptions that will do the job and let exceptions you can't handle bubble up to the caller.

  2. Supports the use of a plain value as well as a function for the failure value. This saves you having to use a lambda in a lot of cases. (Of course, instead of lambda: '' you can just use str.)


def try_except(success, failure):
    try:
        return success()
    except:
        return failure()

variable = try_except(do_some_file_loading_stuff, lambda: '')

I think the code is self explanatory. It returns the value returned by success unless there is an error, then it returns the value returned by failure. If do_some_file_loading_stuff is an expression rather than just a function call, wrap it in a lambda as well.

Edit: @kindall and I improved his version a bit so it's just as fast as mine, can be called exactly the same if you want, has more features, and is the same number of lines. Use it!

def try_except(success, failure, *exceptions):
    try:
        return success()
    except exceptions or Exception:
        return failure() if callable(failure) else failure

Tags:

Python