F-Strings
Concepts covered: f-strings
An f-string is a string literal with an f before the opening quote. Each pair of braces inside it holds a Python expression; when the line runs, Python evaluates the expression, converts the result to text, and puts that text in place of the braces.
table = "orders"
rows = 1500
print(f"Loaded {rows} rows into {table}")
print(f"{table.upper()} has {rows // 100} hundred rows")
print("Loaded " + str(rows) + " rows into " + table)Output:
Loaded 1500 rows into orders ORDERS has 15 hundred rows Loaded 1500 rows into orders
The concatenated version needs str(rows), because + between a string and an int raises TypeError. The f-string converts for you, and the sentence reads in one piece with each value where it appears. {rows // 100} and {table.upper()} put arithmetic and method calls inside the braces, which accept any expression.
Indexes, slices and searches inside the braces
uri = "spotify:track:6rqhFgbbKwnb9MLmUQDhG6"
track_id = uri[uri.rfind(":") + 1:]
print(f"https://open.spotify.com/track/{track_id}")
print(f"id length: {len(track_id)}")
print(f"kind: {uri[8:13]}, first: {track_id[0]}")Output:
https://open.spotify.com/track/6rqhFgbbKwnb9MLmUQDhG6 id length: 22 kind: track, first: 6
Everything from the earlier sections works inside braces. The ID comes from slicing after the last colon, and the share link is assembled around it. len and an index also run in place. A long expression is clearer as a variable of its own, as track_id is here, which keeps the template readable.
Formatting numbers after a colon
revenue = 1299.5
share = 0.125
events = 2500000
month = 3
print(f"{revenue:.2f}")
print(f"{share:.1%}")
print(f"{events:,}")
print(f"2024-{month:02}-15")Output:
1299.50 12.5% 2,500,000 2024-03-15
A colon after the expression starts a format spec. .2f prints a float with exactly 2 decimals. .1% multiplies by 100 and adds a percent sign, and , groups thousands. For 02, Python pads with zeros to a width of 2. Zero padding matters in dates and partition paths: as text, month=10 sorts before month=3, while month=03 sorts before month=10.
Mixing slices and specs in one line
track_id = "6rqhFgbbKwnb9MLmUQDhG6"
plays = 1820
total = 14560
print(f"{track_id[:6]}: {plays:,} plays, {plays / total:.1%} of the day")Output:
6rqhFg: 1,820 plays, 12.5% of the day
Each spec applies only to the value in its own braces, so one f-string can hold a slice with no spec, a count grouped with ,, and a ratio shown with .1%. The division happens inside the braces and gives 0.125; the spec decides how that float looks and leaves the computed value alone.
Braces, quotes and the = shortcut
key = "region"
value = "eu-west"
print(f'{{"{key}": "{value}"}}')
print(f"{key=}")
print(f"{len(value)=}")Output:
{"region": "eu-west"}
key='region'
len(value)=7Doubled braces {{ and }} print 1 literal brace each, which JSON-shaped text needs. Writing = after an expression prints the expression and its value joined by an equals sign, with quotes around strings: key='region'. Before Python 3.12, including the 3.9 these examples run on, quotes inside the braces must differ from the ones around the f-string: f"{name.replace('-', '_')}" works, and reusing double quotes inside is a SyntaxError. From 3.12 on, reusing the same quotes is allowed.
When the values are read
status = "running"
msg = f"job is {status}"
status = "done"
print(msg)
print(f"job is {status}")Output:
job is running job is done
An f-string is evaluated once, on the line where it appears. msg holds the finished text job is running, and changing status afterwards can't reach back into it. The second print evaluates a fresh f-string, so it sees done.
for hour in range(3):
print(f"hour={hour:02}")Output:
hour=00 hour=01 hour=02
Inside a loop, the f-string sits on a line that runs once per pass, so each pass evaluates it with that pass's hour. A job that writes one partition per hour runs the same template 24 times and gets 24 different paths, from hour=00 to hour=23.
What does this program print?
part = 4
total = 12
print(f"{{part}} {part}/{total} {part / total:.1%}")- {4} 4/12 33.3%
- {part} 4/12 0.3%
- {part} 4/12 33.3%
- 4 4/12 33.3%
About this lesson
This section is part of the Strings: Intermediate lesson on DataDriven, the home of data engineering. Lessons cover SQL, Python, Spark, data modeling and pipeline architecture, and each section pairs its explanation with worked examples and practice you run as you go.