Adam Johnson

Home | Blog | Training | Projects | Colophon | Contact

Simplify Your If Statements That Return Booleans

2020-01-17

Here’s a hint I have found myself repeating in code review. I learnt this from my university lecturer Tony Field, who probably repeated it in every lecture! He was teaching us Haskell, but it applies to Python, and most other programming languages.

Take a look at this code:

def is_frazzable(widget):
    if widget.frobnications >= 12:
        return True
    else:
        return False

While clear and correct, it’s longer than it needs to be. The function body can be simplified - down to one line!

if takes a boolean expression - a Python bool. Here the expression is widget.frobnications >= 12. Our code then returns a bool: True if the expression is True, and False if the expression is False.

We can remove this redundant redundancy by returning the expression instead:

def is_frazzable(widget):
    return (widget.frobnications >= 12)

(The brackets are not necessary in Python, but I like keeping them for clarity.)

In general, any expression of the form:

if x:
    return True
else:
    return False

…can be simplified to:

return bool(x)

The wrapping call to bool is unnecessary if the expression already returns a bool. This at least all comparison and boolean operators (==, in, and, etc.).

Assignments

If you’re not returning but instead assigning a new variable:

if widget.frobnications >= 12:
    is_frazzable = True
else:
    is_frazzable = False

…this can also be simplified to:

is_frazzable = (widget.frobnications >= 12)

In general, that means code looking like:

if x:
    y = True
else:
    y = False

…can be simplified to:

y = x

One Line Format

Python also has the single line if format, for example:

is_frazzable = True if widget.frobnications >= 12 else False

…this can be simplified as above:

is_frazzable = (widget.frobnications >= 12)

Negated

If you’re returning the negation of an expression (reversed True / False):

if widget.frobnications >= 12:
    return False
else:
    return True

…this can be simplified using not:

return not (widget.frobnications >= 12)

You might be able to simplify further by swapping to the opposite operator(s) and removing the not. For example here >= can be swapped to <:

return (widget.frobnications < 12)

Single Exit

If you’re also doing something on one path only, you can simplify with this pattern too. For example, if we wanted log a message when encountering unfrazzable widgets:

def is_frazzable(widget):
    if widget.frobnications >= 12:
        return True
    else:
        logger.warning("Unfrazzable widget found, ID %s",  widget.id)
        return False

We can separate it by storing the boolean result in a variable and returning it after logging:

def is_frazzable(widget):
    frazzable = (widget.frobnications >= 12)
    if not frazzable:
        logger.warning("Unfrazzable widget found, ID %s",  widget.id)
    return frazzable

This is one line shorter, and also has the advantage of a single return at the end of the function.

Update (2020-01-18): Thanks to Tom Grainger for pointing out it's possible to write this example with Python 3.8's Walrus Operator. This saves another line by doing the assignment inside the if:

def is_frazzable(widget):
    if not (frazzable := widget.frobnications >= 12):
        logger.warning("Unfrobnicated widget found, ID %s",  widget.id)
    return frazzable

Fin

Hope this helps you write clearer code! If I sent you this article in code review, thanks for taking the time to read.

—Adam


Are your Django project's tests slow? Read Speed Up Your Django Tests now!


Subscribe via RSS, Twitter, or email:

One summary email a week, no spam, I pinky promise.

Related posts:

Tags: python