How To Handle Exceptions in Python (vs JavaScript)

In this episode of Python for JavaScript developers: how to handle exceptions in Python, how to create your own, and how to raise them.

How To Handle Exceptions in Python (vs JavaScript)

So, you’ve been developing with JavaScript since forever and now you want to approach Python, but don’t know where to start? I’m a Python lover myself, and this series is for you.

In this episode you’ll learn how Python compares to JavaScript when it comes to handling exceptions and errors. Enjoy!

Requirements

To follow along you need at least a basic understanding of JavaScript and its quirks. This series is not an exhaustive guide to both languages, rather, a 10.000 feet comparison between them.

The complete series

Missed an episode? Here we go:

How to handle exceptions in Python: what is an exception?

Would be nice if programs could always work well. But the real world is a bit wild. If a program can fail it certainly will.

Consider a simple Python function. What can go wrong here?

def divide(a, b):
    result = a / b
    return result


divide(89, 6)
divide(89, "6")
divide(89, 2)

Save the code in a file (I called mine exceptions.py) and run it. You’ll see a lot of stuff, and more important, a TypeError:

TypeError: unsupported operand type(s) for /: 'int' and 'str'

It comes from the second call to divide, where we tried to divide a number and a string, which is invalid in Python (and in JavaScript as well). The program stops, never reaching the third function call.

What Python does here is raising an exception, that is, an exceptional event that blows up our code.

So exceptions are serious errors that most of the time can halt a program. How we handle exceptions makes the difference between a failing program and one that could recover by itself.

Handling synchronous exceptions in Python and JavaScript

If we stay in a synchronous world, Python and JavaScript are pretty similar when it comes to handling exceptions.

In Python there is try/except where try should include the “happy path” of your code, while except will print or forward the error somewhere else.

The previous example can be refactored to:

def divide(a, b):
    try:
        return a / b
    except TypeError:
        print("Oops!")

divide(89, 6)
divide(89, "6")
divide(89, 2)

Notice that you should specify the error type on except, TypeError in our case.

try/except means more or less: try this code, if it fails intercept the error and do something else.

Now the program prints “Oops!”, but it does not stops anymore. All function calls (except the one that errors out) continue to run.

Great job! You discovered how to handle exceptions in Python! But how about JavaScript?

Consider the following example (JavaScript):

function find(member, target) {
  return member in target;
}

find("a", "siena");

It’s an invalid use of the in operator (it works only on objects).

Run the code and you should see:

TypeError: Cannot use 'in' operator to search for 'a' in siena

Ok JavaScript, fair enough. To handle errors, in JavaScript there is try/catch, where try has the “happy path”, while catch deals with the problem.

We can rewrite the code (with another call to find for testing the program) to:

function find(member, target) {
  try {
    return member in target;
  } catch (err) {
    console.log("Oops!");
  }
}

find("a", "siena");
var result = find("city", { name: "Jane", city: "London" });
console.log(result);

Now the program prints “Oops!”, “true”, and does not stops anymore.

Notice the parameter err? Let’s see in the next section how to use it.

How to handle exceptions: using the error message in Python and JavaScript

Handling exceptions is great and all, but printing “Oops” not so. Would be nice to print the error message instead.

In JavaScript you can use the parameter for catch, most of the times called error or err as a convention. It contains the actual exception object.

In turn, almost every exception has a property called message, with the actual text error. The previous JavaScript example becomes:

function find(member, target) {
  try {
    return member in target;
  } catch (err) {
    console.log(err.message);
  }
}

find("a", "siena");
var result = find("city", { name: "Jane", city: "London" });
console.log(result);

which prints:

Cannot use 'in' operator to search for 'a' in siena
true

Way better than “Oops”.

In Python you can do the same, with as:

def divide(a, b):
    try:
        return a / b
    except TypeError as err:
        print(err)

The example speaks for itself: intercept TypeError and create a binding named err for convenience. Then print the error.

Raising your own exceptions in Python and JavaScript

As with almost anything in programming, the terminology is blurry, even for simplest things.

Take the term throw for example. It’s common to say “throwing” in JavaScript when we developers need to terminate the program and say, “ehi, this is not good, let’s stop”.

Errors can be thrown by the JavaScript engine or on purpose by developers when checking for invalid values.

In the Python world instead we say “raising” instead of throwing, and errors are “exceptions”.

But why would you raise or throw an error? Consider the JavaScript example again. We know that the in operator works well only on objects.

If we check the parameter target we can throw an error when it’s a string. Here’s how:

function find(member, target) {
  if (typeof target === "string")
    throw Error("Target must be an object, got string");

  try {
    return member in target;
  } catch (err) {
    console.log(err.message);
  }
}

Notice the use of the Error built-in object for creating a new custom error. Now call the function:

find("a", "siena");

The net effect of adding throw is that the consumer of this function will get the error back:

Error: Target must be an object, got string

This is expected, we want to stop the execution if target is a string, so the code will never reach the try block.

Now let’s go back to Python. We left with this code:

def divide(a, b):
    try:
        return a / b
    except TypeError as err:
        print(err)

Here we can check if both parameters are numbers before dividing them, and then throw an error. The throw counterpart in Python is called raise:

def divide(a, b):
    if isinstance(a, str) or isinstance(b, str):
        raise TypeError("Expected int, got object")
    try:
        return a / b
    except TypeError as err:
        print(err)

When calling the function with:

divide(1, "2")

you should see:

TypeError: Expected int, got object

Notice this time the use of TypeError for creating a custom error message. If you want you can also extend Exception and create your own custom exception:

class CustomError(Exception):
    pass


def divide(a, b):
    if isinstance(a, str) or isinstance(b, str):
        raise CustomError("Expected int, got object")
    try:
        return a / b
    except TypeError as err:
        print(err)


divide(1, "2")

As an alternative to raise we can also use assert, handy for debugging in development:

def divide(a, b):
    assert isinstance(a, str), "Expected int, got object"
    assert isinstance(a, str), "Expected int, got object"
    try:
        return a / b
    except TypeError as err:
        print(err)


divide(1, "2")

How to handle exceptions in Python: wrapping up

For handling synchronous exceptions, both Python and JavaScript have a similar construct: try/except for Python, try/catch for JavaScript.

For raising exceptions in JavaScript we use throw, followed by a call to Error (or other siblings like TypeError or SyntaxError).

In Python instead there is raise, used in conjunction with custom exception classes or with classes like ValueError, TypeError, and more, depending on the exception type.

Thanks for reading and stay tuned for more!

Resources

Learn how to recover gracefully from ORM errors in Django

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.