Errors should never pass silently

Bob, Wed 18 January 2017, Best practices

anti-patterns, cleancode, error handling, exceptions, Zen of Python

>>> import this
The Zen of Python, by Tim Peters

Explicit is better than implicit.
Errors should never pass silently.


This is a great read: The Little Book of Python Anti-Patterns. For the more experienced Pythonistas most is well known, yet it is a good refresher and you probably still find something new.

Today a bit about error handling. In our Learning from Python mistakes article we already mentioned not to use pass in except. It is actually the worst anti-pattern (as stated by Andreas Dewes, the author of the book, you can listen to the interview here).

The problem with except: pass

Why is it so bad? See SO for a detailed explanation:

As you correctly guessed, there are two sides to it: Catching any error by specifying no exception type after except, and simply passing it without taking any action.

My explanation is “a bit” longer—so tl;dr it breaks down to this:

  1. Don’t catch any error. Always specify which exceptions you are prepared to recover from and only catch those.
  2. Try to avoid passing in except blocks. Unless explicitly desired, this is usually not a good sign.


The worst offender though is the combination of both. This means that we are willingly catching any error although we are absolutely not prepared for it and we also don’t do anything about it.

So this violates the two Zen aphorisms above. You always want to catch errors explicitly:

>>> try:
...     1/0
... except ZeroDivisionError:
...     print('cannot divide by 0')
cannot divide by 0

You can use else and finally with a try/except as shown in this toy example:

>>> a, b, c = 1, 2, 0
>>> try:
...     a/b
... except ZeroDivisionError:
...     print('cannot divide by 0')
... else:
...     print('division was ok')
... finally:
...     print('this always runs')
division was ok
this always runs
>>> try:
...     b/c
... except ZeroDivisionError:
...     print('cannot divide by 0')
... else:
...     print('division was ok')
... finally:
...     print('this always runs')
cannot divide by 0
this always runs

One thing to watch out for is except clause order if you have more than one: always go from more specific to more generic (bottom to top in the inheritance chain), for example:

>>> ZeroDivisionError.__mro__
(<class 'ZeroDivisionError'>, <class 'ArithmeticError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>)

(about mro)

Asking for permission instead of forgiveness

It becomes even more important because the Python community uses an EAFP (easier to ask for forgiveness than permission) coding style.

I have done this a lot:

if os.path.exists("file.txt"):

But the Pythonic way to do it is:

    # assume the file is there
except OSError:
    # if not, handle the (explicit) error

Hence, more reason to manage exceptions well!

Custom exceptions

Another great way to make your code more readable and taking exceptions to the next level is to write your own. Sounds scary? It is actually pretty easy as this great post shows:

class NameTooShortError(ValueError):

def validate(name):
    if len(name) < 10:
        raise NameTooShortError(name)

A bit more involved (yet still easy to follow) example from tweepy:

class TweepError(Exception):
    """Tweepy exception"""

    def __init__(self, reason, response=None, api_code=None):
        self.reason = six.text_type(reason)
        self.response = response
        self.api_code = api_code
        Exception.__init__(self, reason)

    def __str__(self):
        return self.reason

Which we used in our Twitter bot:

def post_tweet(self, status):
        logging.debug('posted status {} to twitter'.format(status))
    except TweepError as err:
        logging.error('tweepy update_status error: {}'.format(err))


Recommended reading:

PyBites Python Tips

Do you want to get 250+ concise and applicable Python tips in an ebook that will cost you less than 10 bucks (future updates included), check it out here.

Get our Python Tips Book

"The discussions are succinct yet thorough enough to give you a solid grasp of the particular problem. I just wish I would have had this book when I started learning Python." - Daniel H

"Bob and Julian are the masters at aggregating these small snippets of code that can really make certain aspects of coding easier." - Jesse B

"This is now my favourite first Python go-to reference." - Anthony L

"Do you ever go on one of those cooking websites for a recipe and have to scroll for what feels like an eternity to get to the ingredients and the 4 steps the recipe actually takes? This is the opposite of that." - Sergio S

Get the book