If you're using print
calls to debug your Python code, consider using f-strings with self-documenting expressions instead.
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.
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.
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!
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
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.
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.
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.
Need to fill-in gaps in your Python skills?
Sign up for my Python newsletter where I share one of my favorite Python tips every week.
Sign in to your Python Morsels account to track your progress.
Don't have an account yet? Sign up here.