Python's f-string Debugging Trick That Saves Me Hours of Typing
The Problem
I was debugging a function with a dozen variables, and my code looked like this:
def process_order(order_id, customer_name, items, total, discount, tax): print(f"order_id={order_id}") print(f"customer_name={customer_name}") print(f"items={items}") print(f"total={total}") print(f"discount={discount}") print(f"tax={tax}")
# ... rest of functionI was typing the same variable name twice for every single print statement. It felt wasteful, but I needed to see the variable names alongside their values in the output.
The Repetitive Pattern I Hated
Every debug session looked like this:
x = 10y = 20name = "Alice"scores = [85, 92, 78]
print(f"x={x}") # x=10print(f"y={y}") # y=20print(f"name={name}") # name=Aliceprint(f"scores={scores}") # scores=[85, 92, 78]I typed x twice. Then y twice. Then name twice. Every. Single. Time.
Then I discovered Python 3.8 has a feature that does this automatically.
The Solution: f-string Equals Syntax
I found out about the = specifier in f-strings, introduced in Python 3.8:
x = 10y = 20name = "Alice"scores = [85, 92, 78]
print(f"{x=}") # x=10print(f"{y=}") # y=20print(f"{name=}") # name='Alice'print(f"{scores=}") # scores=[85, 92, 78]The output shows both the variable name AND its value. I only type the variable name once.
How It Works
When I use f"{variable=}", Python prints the variable name, an equals sign, and the repr of the value.
value = 42text = "hello"
print(f"{value=}") # value=42print(f"{text=}") # text='hello'Notice that strings get quotes in the output. That’s because it uses repr() internally, not str().
It Works With Expressions Too
I was surprised that this works with expressions, not just variables:
x = 10y = 20
print(f"{x + y=}") # x + y=30print(f"{len('hello')=}") # len('hello')=5print(f"{x * 2=}") # x * 2=20Python prints the exact expression I wrote, then the result. This is useful for quick calculations during debugging.
Spacing Is Preserved
I noticed that the spacing in my expression is preserved in the output:
name = "Alice"
print(f"{name=}") # name='Alice'print(f"{name =}") # name ='Alice'print(f"{name = }") # name = 'Alice'The output matches what I typed. If I add spaces around the =, they appear in the output too.
Before and After Comparison
Here’s how my debugging code changed:
Before (Python 3.7 and earlier):
def calculate_discount(price, quantity, discount_rate, tax_rate): print(f"price={price}") print(f"quantity={quantity}") print(f"discount_rate={discount_rate}") print(f"tax_rate={tax_rate}")
subtotal = price * quantity print(f"subtotal={subtotal}")
discount = subtotal * discount_rate print(f"discount={discount}")
total = subtotal - discount print(f"total={total}")
return totalAfter (Python 3.8+):
def calculate_discount(price, quantity, discount_rate, tax_rate): print(f"{price=}") print(f"{quantity=}") print(f"{discount_rate=}") print(f"{tax_rate=}")
subtotal = price * quantity print(f"{subtotal=}")
discount = subtotal * discount_rate print(f"{discount=}")
total = subtotal - discount print(f"{total=}")
return totalSame output, less typing. The output for both:
price=100quantity=5discount_rate=0.1tax_rate=0.08subtotal=500discount=50.0total=450.0A Real Debugging Session
I was tracking down a bug in a data processing function. Here’s what my debug output looked like:
def process_user_data(users, filters, settings): print(f"{len(users)=}") print(f"{filters=}") print(f"{settings=}")
active_users = [u for u in users if u.get('active')] print(f"{len(active_users)=}")
filtered = [u for u in active_users if u.get('age', 0) > 18] print(f"{len(filtered)=}")
results = apply_settings(filtered, settings) print(f"{len(results)=}")
return resultsThe output:
len(users)=150filters={'min_age': 18, 'status': 'active'}settings={'limit': 100, 'sort': 'desc'}len(active_users)=120len(filtered)=85len(results)=85I could quickly see where my data was getting filtered. The len(users)= syntax let me show the expression AND its result in one line.
Formatting Still Works
I can combine the = specifier with format specifiers:
price = 123.456789ratio = 0.12345
print(f"{price=:.2f}") # price=123.46print(f"{ratio=:.2%}") # ratio=12.35%This is useful when I need to see rounded values during debugging.
Gotchas I Learned
Gotcha 1: It Uses repr(), Not str()
name = "Alice"
print(f"{name}") # Alice (str)print(f"{name=}") # name='Alice' (repr)The quotes appear because repr() shows the string representation. This is actually helpful because I can see the type of the value.
Gotcha 2: Complex Expressions Can Be Hard to Read
data = {'users': [{'name': 'Alice', 'age': 30}]}
print(f"{data['users'][0]['name']=}") # data['users'][0]['name']='Alice'The expression gets printed verbatim, which can look messy. For complex access patterns, I prefer:
data = {'users': [{'name': 'Alice', 'age': 30}]}first_user_name = data['users'][0]['name']
print(f"{first_user_name=}") # first_user_name='Alice'Gotcha 3: Only Works in Python 3.8+
# This will raise SyntaxError in Python 3.7 and earlierx = 10print(f"{x=}") # SyntaxError in Python < 3.8If you’re stuck on an older Python version, you’ll have to use the old way:
x = 10print(f"x={x}") # Works in all Python 3 versionsWhen I Actually Use This
I use the = specifier in these scenarios:
1. Quick debugging print statements:
def fetch_data(url, timeout, retries): print(f"{url=}, {timeout=}, {retries=}") # One line, all values # ... fetch logic2. Checking intermediate calculations:
def calculate_total(items): subtotal = sum(item['price'] for item in items) tax = subtotal * 0.08 total = subtotal + tax
print(f"{subtotal=}, {tax=}, {total=}") # See all at once return total3. Logging variable state in try/except blocks:
try: result = risky_operation(data)except Exception as e: print(f"Error: {e=}") print(f"{data=}") raiseWhen I Don’t Use It
I don’t use this for production logging or user-facing messages. It’s purely for debugging during development.
# DON'T use for user messagesprint(f"Your balance is: {balance=}") # Confusing for users
# DO use for debug output# print(f"{balance=}") # Good for debuggingSummary
Python 3.8’s f-string equals syntax (f"{variable=}") saves me from typing variable names twice when debugging. It prints both the expression and its value automatically.
Key points:
- Use
f"{variable=}"instead off"variable={variable}" - Works with expressions:
f"{x + y=}" - Preserves spacing in the output
- Uses
repr()for values (strings show quotes) - Requires Python 3.8 or later
This is one of those small quality-of-life improvements that I use daily. It’s not going to change how I write production code, but it makes debugging sessions much less tedious.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments