Juha-Matti Santala
Community Builder. Dreamer. Adventurer.

F is for f-strings - Python A to Z

Code in this blog post was written with versions: Python: 3.14

Python A-Z is a blog series about Python. Each day, I share insights, ideas and examples for different parts of Python development that match with the letter of the day. Blaugust is an annual blogging festival in August where the goal is to write a blog post every day of the month.

Programming languages have many ways to combine literal strings and variables. For a decade now, we in Python land have been able to enjoy the beauty and elegance of f-strings.

f-string is a string that is prefixed with the letter f:

string_type = 'f-string'
print(f'This is a {string_type}')

When you craft an f-string, you can evaluate Python code inside it by placing it inside curly braces `{ … }`.

In addition to simply putting in a variable, there are a bunch of format specifications that allow further modification of the output. fstring.help has a really handy reference sheet for these but here are some that I use regularly.

Padding numbers

File browsers usually default to sorting alphabetically so if you have files 1.json, 2.json and 10.json, the 10 will sort before the 2. So to keep things neat and tidy, I often left-pad with zeroes to force proper sorting:

for filename in range(1, 20):
  print(f'{filename:02d}')
  
# Prints 01, 02, 03, ... 20

Here 0 is the value we use to fill and 2 is the width to how many characters we want to pad up to.

Aligning text

When I build command line tools, I want a well-defined output structure and aligning items left or right with a given width is helpful.

name, goals = 'Juhis', 20
print(f'{name:<10}{goals:>5}')
# 'Juhis        20'

< is for left-align, > is for right-align, ^ would be for center and the number is the width. In this example, it guarantees that the name field is at least 10 characters and goals field is 5.

You can combine this with the previous example if you want to fill the empty space with something else, like underscore:

item, value = 'Cucumber', 14
print(f'{item:_<10}{value:_>5}')
# Cucumber_____14

Debugging

For debugging, I use two formats. (Btw, if you wanna get better at debugging, check out Debugging Python and if you’re curious about why printing is a good debug tool, read print is your best debugging tool.)

The first one uses = sign to print out the name of the variable and its value separated with an equal sign. It’s a short hand for f'value={value}' .

unknown = 400
print(f'{unknown=}, {unknown = }') # Whitespace is preserved
# unknown=400, unknown = 400

The second one uses !r to print out object’s __repr__ value.

class Card:
	def __init__(self, name, number):
	  self.name = name
	  self.number = number
	  
	def __repr__(self):
	  return f'Card("{self.name}", {self.number})'

card = Card('Pikachu', 25)
print(f'{card!r}')
# Card("Pikachu", 25)

Percentages

The last one is actually something I didn’t know about before I started writing this but can be handy. You can convert floats to percentages with :.0%:

percent = 0.3738
print(f'{percent:.0%}')
# 37%

print(f'{percent:.2%}')
# 37.38%

It’s pretty handy!


If something above resonated with you, let's start a discussion about it! Email me at juhis@hamatti.org and share your thoughts. This year, I want to have more deeper discussions with people from around the world and I'd love if you'd be part of that.