Strings and f-Strings
In Chapter 47, you wrote name: str = "James" and moved on. A string was just a label, a value you stored and printed. Now strings become your primary data type for building SmartNotes: titles, note bodies, formatted reports, tag lists. You need to do more than store text. You need to build it, format it, and measure it.
Emma pulls up a SmartNotes requirement. "We need a function that displays a note summary: the title, word count, and reading time, all in one line. How would you build that string?"
James tries concatenation: "Title: " + title + " Words: " + str(word_count). It works, but it is ugly and fragile.
"There is a better way," Emma says. She types an f before the opening quote.
Three Ways to Create Strings
Python gives you three quote styles. Each serves a different purpose:
# Single quotes: simple text
greeting: str = 'Hello, World!'
# Double quotes: same as single quotes (use either consistently)
greeting: str = "Hello, World!"
# Triple quotes: text that spans multiple lines
note_body: str = """This is the first line.
This is the second line.
This is the third line."""
Output (from print statements):
Hello, World!
Hello, World!
This is the first line.
This is the second line.
This is the third line.
Single and double quotes are interchangeable. Pick one style and use it consistently. Triple quotes preserve line breaks, which makes them useful for multi-line text like note bodies or descriptions.
Single quotes ('hello') and double quotes ("hello") create identical strings. Python does not care which you use. The convention in most Python projects is double quotes. Triple quotes ("""...""") let you write text across multiple lines without any special characters.
f-Strings: Embedding Data in Text
An f-string starts with f before the opening quote. Inside the string, curly braces {} hold expressions that Python evaluates and inserts:
name: str = "James"
age: int = 30
intro: str = f"{name} is {age} years old"
Output:
James is 30 years old
You can put any expression inside the braces, not just variable names:
word_count: int = 1500
wpm: int = 250
summary: str = f"Reading time: {word_count / wpm} minutes"
Output:
Reading time: 6.0 minutes
Format Specifiers
The number 6.0 is fine, but what if the division produces 6.123456789? You can control the display with a format specifier after a colon:
word_count: int = 1500
wpm: int = 250
summary: str = f"Reading time: {word_count / wpm:.1f} minutes"
Output:
Reading time: 6.0 minutes
The :.1f means "one decimal place, fixed-point." Here are the format specifiers you will use most often:
| Specifier | Meaning | Example | Result |
|---|---|---|---|
:.1f | 1 decimal place | f"{3.14159:.1f}" | "3.1" |
:.2f | 2 decimal places | f"{3.14159:.2f}" | "3.14" |
:, | Thousands separator | f"{1500000:,}" | "1,500,000" |
Python's f-string format specifiers follow the same mini-language as str.format(). The :.1f syntax works identically in both. f-strings are preferred in modern Python because they are more readable and faster.
Escape Sequences
Some characters have special meaning inside strings. To include them literally, you use a backslash \ as an escape character:
# Newline: \n starts a new line
header: str = "Title\tWord Count\nMy Note\t350"
# Tab: \t inserts a horizontal tab
row: str = "Python\t85\tPassed"
# Backslash: \\ produces a single backslash
path: str = "C:\\Users\\James\\notes.txt"
Output (from print statements):
Title Word Count
My Note 350
Python 85 Passed
C:\Users\James\notes.txt
| Escape | What It Produces | When You Need It |
|---|---|---|
\n | New line | Multi-line output from a single string |
\t | Tab | Aligning columns in text |
\\ | Single backslash | File paths on Windows |
\" | Double quote | Quotes inside a double-quoted string |
Measuring Strings with len()
The built-in len() function returns the number of characters in a string, including spaces and special characters:
title: str = "SmartNotes"
length: int = len(title)
Output:
10
Spaces count:
greeting: str = "Hello, World!"
len(greeting)
Output:
13
An empty string has length zero:
empty: str = ""
len(empty)
Output:
0
len() works on any sequence, not just strings. You will use it again with lists and dicts in Lesson 4.
PRIMM-AI+ Practice: Building f-Strings
Predict [AI-FREE]
Look at these f-strings. Without running anything, predict the exact output of each one. Write your predictions and a confidence score from 1 to 5 before checking.
name: str = "Alice"
score: int = 92
total: int = 100
line1: str = f"{name} scored {score}/{total}"
line2: str = f"Percentage: {score / total * 100:.1f}%"
line3: str = f"Name length: {len(name)}"
Check your predictions
line1: "Alice scored 92/100". The braces insert the variable values directly. The / between {score} and {total} is literal text, not division.
line2: "Percentage: 92.0%". The expression score / total * 100 evaluates to 92.0, and :.1f formats it to one decimal place. The % after the closing brace is literal text.
line3: "Name length: 5". len(name) evaluates to 5 because "Alice" has 5 characters.
If you got all three correct, your f-string intuition is solid. The tricky part is recognizing which / and % are operators and which are literal text.
Run
Create a file called fstring_practice.py with the three f-strings above. Add print() calls for each one. Run it with uv run python fstring_practice.py. Compare the output to your predictions.
Investigate
For any prediction that was wrong, write one sentence explaining what you misunderstood. Focus on the difference between expressions inside {} (evaluated by Python) and text outside {} (printed literally).
Modify
Change score to 78 and total to 90. Predict the new output of all three lines before running. Did line3 change? (It should not, because len(name) does not depend on score or total.)
Make [Mastery Gate]
Without looking at any examples, write 3 f-strings for SmartNotes:
- An f-string that shows a note title and word count:
"My Note: 350 words" - An f-string that calculates and displays reading time with one decimal place
- An f-string that shows the note title length
Run your file with uv run python to verify the output matches what you expect.
Try With AI
If Claude Code is not already running, open your terminal, navigate to your SmartNotes project folder, and type claude. If you need a refresher, Chapter 44 covers the setup.
Prompt 1: Check Your f-String Understanding
I'm learning Python f-strings. Here is my understanding:
"An f-string evaluates expressions inside curly braces at
runtime, and :.1f means one decimal place." Is my summary
accurate? What details am I missing?
Read AI's response. Did it mention that the format specifier goes after a colon inside the braces? Did it explain that the expression can be any valid Python expression, not just variable names? Compare its answer to what you learned in this lesson.
What you're learning: You are verifying your mental model by stating it confidently and letting AI find gaps. This is the same verify-then-refine pattern you use when reviewing AI-generated code.
Prompt 2: Generate Formatted Output
Write 5 Python f-strings for a simple note-taking app.
Each f-string should format different data: a title with
word count, a reading time with one decimal place, a
percentage complete, a file path, and a multi-part summary
using at least two variables. Use type annotations on all
variables.
Read AI's output. Check: did it use :.1f for the reading time? Did it use type annotations on every variable? Are the f-string expressions correct? If anything looks wrong, tell AI what to fix and why.
What you're learning: You are reviewing AI-generated string formatting against the rules from this lesson. Spotting format specifier errors now saves debugging time later.
Key Takeaways
-
Three quote styles serve different purposes. Single and double quotes create identical strings. Triple quotes preserve line breaks for multi-line text.
-
f-strings evaluate expressions inside
{}. You can embed variables, arithmetic, function calls, and format specifiers like:.1fdirectly in the string. -
Escape sequences produce special characters.
\ncreates a new line,\tcreates a tab,\\produces a literal backslash. -
len()counts characters including spaces. An empty string""has length 0. This function works on any sequence type, not just strings.
Looking Ahead
You can now create and format strings. In Lesson 2, you reach inside them: title[0] gives you the first character, title[5:] gives you everything from position 5 onward. Indexing and slicing let you extract exactly the parts you need.