# Exceptions In Python

> An overview look at custom exceptions in Python

- Canonical: https://dennisokeeffe.com/blog/2021-08-03-exceptions-in-python
- Published: 2021-08-03
- Updated: 2021-08-03
- Tags: beginner, python, 100daysofpython

> This is Day 15 of the #100DaysOfPython challenge.

This post will look at home exceptions are rescued and will demonstrate how to handle different exceptions raised.

## Prerequisites

1. Familiarity with [Pipenv](https://pipenv.pypa.io/en/latest/). See [here](https://blog.dennisokeeffe.com/blog/2020-07-04-abcs-of-pipenv) for my post on Pipenv.
2. Familiarity with [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/gettingstarted/install.html). See [here](https://blog.dennisokeeffe.com/blog/2021-07-19-hello-jupyter-notebook) for my post on JupyterLab.

## Getting started

Let's create the `hello-python-exceptions` directory and install Pillow.

```s
# Make the `hello-python-exceptions` directory
$ mkdir hello-python-exceptions
$ cd hello-python-exceptions

# Init the virtual environment
$ pipenv --three
$ pipenv install --dev jupyterlab
```

Now we can start up the notebook server.

```s
# Startup the notebook server
$ pipenv run jupyter-lab
# ... Server is now running on http://localhost:8888/lab
```

The server will now be up and running.

## Creating the notebook

Once on http://localhost:8888/lab, select to create a new Python 3 notebook from the launcher.

Ensure that this notebook is saved in `hello-python-exceptions/docs/<your-file-name>`.

We will create four cells to handle four parts of this mini project:

1. A demonstration on how `try/except` works.
2. Looking at raising an error from a function.
3. Creating and using custom errors.

## Try/Except

We can use the `try/except` statement to handle errors. You `raise` an `Exception` whenever you want to throw an error from a code block.

The `Exception` is self can then be delegated higher up the code chain to be handled.

For example, if we execute this in our first JupyterLab code block:

```py
try:
  raise Exception('You shall not pass')
  print('Success')
except:
  print('There was an issue')
```

We notice the output is `There was an issue`. We do not make it passed the raised exception.

We can also capture exceptions by their type. For example, if we execute this in our second JupyterLab code block:

```py
try:
  raise Exception('You shall not pass')
  print('Success')
except Exception:
  print('Did not make it to final catch-all block')
except:
  print('There was an issue')
```

You will notice that `'Did not make it to final catch-all block'` was captured and printed, where as the final `except` code block is used a capture all.

## Raising an error from a function

Defining a function that raises an error will traverse up the code block to the top level.

```py
def example_exception():
  raise Exception('You shall not pass')

def example_fn():
  example_exception()

try:
  example_fn()
except:
  print('There was an issue')
```

This also prints out `'There was an issue'`.

## Creating and using custom errors

We can create custom errors simply by defining a class that extends `Exception`.

```py
class CustomError(Exception):
    """Custom error"""
    pass
```

We can see this in action working randomly when we use the `randrange` function as a helper to determine which error to raise:

```py
from random import randrange

# define Python user-defined exceptions
class CustomError(Exception):
    """Raised when using a custom error"""
    pass

def example_exception():
  val = randrange(10)
  if val <= 5:
    raise CustomError('You shall not pass')
  else:
    raise Exception("There was an error")

try:
  example_exception()
except CustomError as e:
  print(e)
except Exception as e:
  print(e)
```

Running this code in a block will print out `'You shall not pass'` or `'There was an error'` based on the random value.

That means that our `CustomError` is being handled in the `except CustomError as e` block.

## Summary

Today's post demonstrated how to create custom errors by extending `Exception` and demonstrating how errors are raised in a simple manner.

Managing errors in Python is a necessity when working with more complex code that requires more fine-grained control over the possible error outcomes.

## Resources and further reading

1. [The ABCs of Pipenv](https://blog.dennisokeeffe.com/blog/2020-07-04-abcs-of-pipenv)
2. [Hello, JupyterLab](https://blog.dennisokeeffe.com/blog/2021-07-19-hello-jupyter-notebook)
3. [Pipenv](https://pipenv.pypa.io/en/latest/)
4. [Python Exceptions - An Introduction](https://realpython.com/python-exceptions/)
5. [User Defined Exceptions in Python](https://www.programiz.com/python-programming/user-defined-exception)

_Photo credit: [`freestocks`](https://unsplash.com/@freestocks)_
