There is a lot of Python code in the wild which does something like:

raise ValueError("Could not fraz the buzz:"
                 f"{foo} is less than {quux}")

This is, in general, a bad idea. It does not matter if the exception is fairly generic, like ValueError or specific like CustomFormatParsingException.

Exceptions are not program panics. Program panics are things which should "never happen", and usually abort either the entire program, or at least an execution thread.

While exceptions sometimes do terminate the program, or the execution thread, with a traceback, they are different in that they can be caught.

The code that catches the exception will sometimes have a way to recover: for example, maybe it’s not that important for the application to fraz the buzz if foo is 0. In that case, the code would look like:

try:
    some_function()
except ValueError as exc:
    if ???

Oh, right. We do not have direct access to foo. If we formatted better, using repr, at least we could tell the difference between 0 and "0": but we still would have to start parsing the representation out of the string.

Because of this, in general, it is better to raise exceptions like this:

raise ValueError("Could not fraz the buzz: foo is too small", foo, quux)

Note that all the exceptions defined in core Python already allow any number of arguments. Those arguments are available as exc.args, if exc is the exception object. If you do end up defining your custom exceptions, the easiest thing is to avoid overriding the __init__: this keeps this behavior.

Raising exceptions this way gives exception handling a lot of power: it can introspect foo, introspect quux and introspect the string. If by some reason the exception class is raised and we want to verify the reason, checking string equality, while not ideal, is still better than trying to match string parts or regular expression matching.

When the exception is presented to the user interface, in that case, it will not look as nice. Exceptions, in general, should reach the UI only in extreme circumstances. In those cases, having something that has as much information is useful for root cause analysis.

This is an update of an older blog post. Thanks to Mark Rice and Ben Nuttall for their improvement suggestions. All mistakes that are left are my responsibility.


An introduction to zope.interface

Thu 17 October 2019 by Moshe Zadka

This has previously been published on opensource.com.

The Zen of Python is loose enough and contradicts itself enough that you can prove anything from it. Let's meditate upon one of its most famous principles: "Explicit is better than implicit."

One thing that traditionally has been implicit in Python is …

read more

Adding Methods Retroactively

Mon 16 September 2019 by Moshe Zadka

The following post was originally published on OpenSource.com as part of a series on seven libraries that help solve common problems.

Imagine you have a "shapes" library. We have a Circle class, a Square class, etc.

A Circle has a radius, a Square has a side, and maybe Rectangle …

read more

Designing Interfaces

Wed 07 August 2019 by Moshe Zadka

One of the items of feedback I got from the article about interface immutability is that it did not give any concrete feedback for how to design interfaces. Given that they are forever, it would be good to have some sort of guidance.

The first item is that you want …

read more

Interfaces are forever

Fri 12 July 2019 by Moshe Zadka

(The following talks about zope.interface interfaces, but applies equally well to Java interfaces, Go interfaces, and probably other similar constructs.)

When we write a function, we can sometimes change it in backwards-compatible ways. For example, we can loosen the type of a variable. We can restrict the type of …

read more

Analyzing the Stack Overflow Survey

Mon 27 May 2019 by Moshe Zadka

The Stack Overflow Survey Results for 2019 are in! There is some official analysis, that mentioned some things that mattered to me, and some that did not. I decided to dig into the data and see if I can find some things that would potentially interest my readership.

import csv …
read more

Inbox Zero

Wed 15 May 2019 by Moshe Zadka

I am the parent of two young kids. It is easy to sink into random stuff, and not follow up on goals. Strict time management and prioritization means I get to work on open source projects, write programming books and update my blog with a decent cadence. Since a lot …

read more

Publishing a Book with Sphinx

Mon 08 April 2019 by Moshe Zadka

A while ago, I decided I wanted to self-publish a book on improving your Python skills. It was supposed to be short, sweet, and fairly inexpensive.

The journey was a success, but had some interesting twists along the way.

From the beginning, I knew what technology I wanted to write …

read more

A Local LRU Cache

Fri 29 March 2019 by Moshe Zadka

"It is a truth universally acknowledged, that a shared state in possession of mutability, must be in want of a bug." -- with apologies to Jane Austen

As Ms. Austen, and Henrik Eichenhardt, taught us, shared mutable state is the root of all evil.

Yet, the official documentation of functools tells …

read more

Don't Make It Callable

Wed 13 February 2019 by Moshe Zadka

There is a lot of code that overloads the __call__ method. This is the method that "calling" an object activates: something(x, y, z) will call something.__call__(x, y, z) if something is a member of a Python-defined class.

At first, like every operator overload, this seems like a …

read more