Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Debugging with f-strings PREMIUM

Series: Strings
Trey Hunner smiling in a t-shirt against a yellow wall
Trey Hunner
4 min. read 3 min. video Python 3.9—3.13

If you're using print calls to debug your Python code, consider using f-strings with self-documenting expressions instead.

A broken Python program

Here we have a program that makes a random math prompt and then validates whether the answer give by the user is correct:

import random

x = random.randrange(1, 10)
y = random.randrange(1, 10)

answer = input(f"What's {x} multiplied by {y}? ")
expected = x * y

if answer == expected:
    print("Correct!")
else:
    print("That's incorrect")

This program doesn't work right now:

$ python3 check_mult.py
What's 9 multiplied by 8? 72
That's incorrect

Our program always tells us that our answer is incorrect.

Troubleshooting with print

Now, we could try to debug this code by adding some print calls, which will print out what our answer is and what the expected answer is:

import random

x = random.randrange(1, 10)
y = random.randrange(1, 10)

answer = input(f"What's {x} multiplied by {y}? ")
expected = x * y

print("answer:", answer)
print("expected:", expected)

if answer == expected:
    print("Correct!")
else:
    print("That's incorrect")

But the answer and the expected answer look the same right now:

$ python3 check_mult.py
What's 5 multiplied by 1? 5
answer: 5
expected: 5
That's incorrect

Both the answer and the expected answer seem to be 5.

These two values look the same because we're printing out the human-readable string representation, which is what print does by default. While we really wanna be printing out the programmer-readable string representation (with repr):

print("answer:", repr(answer))
print("expected:", repr(expected))

But instead of doing that, let's use f-strings with self-documenting expressions.

Using self-documenting expressions

You can make a self-documenting expression by putting an = sign at the end of an f-string's replacement field (the part between { and }).

print(f"{answer = }")
print(f"{expected = }")

This makes our code a little bit shorter as we're debugging, and also makes the output a little bit more helpful:

$ python3 check_mult.py
What's 6 multiplied by 3? 18
answer = '18'
expected = 18
That's incorrect

Now when we run our program, Python automatically prints out answer = and then the actual result of answer, and it does the same thing with expected:

It's also printing out the programmer-readable representation instead of the human-readable one, which makes it a little bit clearer that answer is currently a string, but it's supposed to be a number.

We should be able to fix our code by turning the answer string into a number using the built-in int function:

import random

x = random.randrange(1, 10)
y = random.randrange(1, 10)

answer = int(input(f"What's {x} multiplied by {y}? "))
expected = x * y

if answer == expected:
    print("Correct!")
else:
    print("That's incorrect")

It looks like we did fix our code:

$ python3 check_mult.py
What's 4 multiplied by 1? 4
Correct!

Self-documenting expressions work with any expression

To make a self-documenting expression you'll start with an f-string:

>>> n = 256
>>> print(f"DEBUGGING {n}")
DEBUGGING 256

Then put an equal sign (=) at the end of one of the replacement fields in that f-string:

>>> n = 256
>>> print(f"DEBUGGING {n=}")
DEBUGGING n=256

That = sign is what turns that replacement field into a self-documenting expression.

That tells Python to print out the expression itself, with an equal sign in between the expression and the result of the expression (usually f-strings just print out the result of the expression).

When I say "expression" I don't just mean a variable: this works with any Python expression that you could put in an f-string:

>>> n = 256
>>> print(f"DEBUGGING {n**2=}")
DEBUGGING n**2=65536

Using format specifiers with self-documenting expressions

Now it's a little bit strange to do this, but you could also use format specifications in a self-documenting expression, if you wanted to. You just have to make sure to put them at the end, after the equal sign.

Here we're telling Python to use commas (,) as a thousand separator:

>>> n = 256
>>> print(f"DEBUGGING {n**2=:,}")
DEBUGGING n**2=65,536

That works, but it's a little bit unusual to see.

Making more readable self-documenting expressions

There is one feature of self-documenting expressions that I really appreciate: you can put spaces around the equal sign to make the result a little bit more readable:

>>> n = 256
>>> print(f"DEBUGGING {n**2 = }")
DEBUGGING n**2 = 65536

It puts spaces around the equal sign in the result.

I pretty much always prefer to put spaces on both sides of the equal sign in my self-documenting expressions.

Summary

If you're debugging Python code with print calls, consider using self-documenting expressions in f-strings to make your debugging a little bit easier.

Series: Strings

Regardless of what you're doing in Python, you almost certainly use strings all the time. A string is usually the default tool we reach for when we don't have a more specific way to represent our data.

To track your progress on this Python Morsels topic trail, sign in or sign up.

0%
This is a free preview of a premium screencast. You have 2 previews remaining.