COMPUTER PROGRAMMING 1 (PYTHON) • PYTHON FUNDAMENTALS

f-String Formatting — I can format output using f-strings and basic rounding/format specifiers at my level.

Master Python's most readable way to embed variables, expressions, and polished numeric output inside strings.

Historical Context & Motivation

From the earliest days of programming, developers have needed a way to combine fixed text with changing data. Imagine you are building a grade calculator: you know the student's name and their score, but you need to produce a single, clean sentence like "Alice scored 92.5%". The challenge is gluing together strings and numbers without the code becoming an unreadable mess. Python has evolved through several approaches to solve this problem, each one more elegant than the last.

1991
Python 1.0 — The % Operator
Python's first string formatting tool borrowed the % operator from the C language. Developers wrote expressions like "Score: %d" % 95. It worked, but the syntax was clunky and error-prone when many variables were involved.
2008
Python 2.6 — str.format()
The .format() method introduced numbered placeholders like "{0} scored {1}".format(name, score). This was more flexible but still forced you to jump back and forth between the template and the argument list.
2015
PEP 498 Proposal
Python core developer Eric V. Smith proposed formatted string literals (f-strings) in PEP 498, arguing that embedding expressions directly inside the string would be faster to write, easier to read, and less bug-prone.
2016
Python 3.6 — f-Strings Arrive
Python 3.6 officially shipped f-strings. Developers could now write f"{name} scored {score}" and Python would evaluate the expressions at runtime. This quickly became the preferred formatting style.
2023
Python 3.12 Enhancements
Python 3.12 relaxed quoting restrictions inside f-string braces, making complex expressions even easier to embed. f-strings are now the community's default choice for string formatting.

So the central question f-strings answer is: How can we embed variables and expressions directly inside a string in the most readable, concise, and powerful way possible? The answer is a single leading f and a pair of curly braces.

Core Principles & Definitions

An f-string (short for formatted string literal) is a string that begins with the letter f or F before the opening quotation mark. Inside the string, any expression wrapped in curly braces {} is evaluated at runtime and its result is inserted into the string. Understanding a few foundational ideas will help you use f-strings confidently.

1

The f-Prefix

Placing f before a string literal tells Python to scan for curly-brace expressions. Without it, {name} is treated as literal text.
2

Expression Slots { }

Anything inside {} is a valid Python expression — a variable, a math operation like {x + y}, or even a function call like {len(items)}.
3

Format Specifiers

A colon : after the expression introduces a format specifier, like {price:.2f} for two decimal places. This gives you precise control over how the value appears.
4

Runtime Evaluation

f-strings are evaluated when the line of code executes, not when the file loads. This means the variables must already exist at that point, or Python will raise a NameError.
5

Readability First

Because the variable sits right where it will appear in the output, you can read an f-string almost like plain English. This makes debugging and maintaining code much easier than older methods.
✦ KEY TAKEAWAY
Think of an f-string like a fill-in-the-blank worksheet. The fixed text is already printed on the page, and the curly braces are the blank lines. When Python reaches that line of code, it writes in the answers (your variable values) and hands you back the completed sentence. The format specifier after the colon is like instructions next to the blank — "round to two decimals" or "pad with spaces" — telling Python how to fill in each blank.

Visual Explanation — Anatomy of an f-String

The diagram breaks an f-string into four labeled parts: the f-prefix activates formatting, expressions are evaluated at runtime, the format specifier controls display, and curly braces mark where each slot begins and ends.

Study the diagram above carefully. Notice how the f prefix sits just before the opening quote — this is what tells Python to look for curly braces inside the string. Everything outside the braces is literal text that appears exactly as written. Inside the braces, Python first evaluates the expression (price * qty), then applies the format specifier (:.2f) to control how the result is displayed. The final output string has no braces left — they have been replaced by the formatted result.

How Format Specifiers Work

The real power of f-strings comes from the format specifier — the mini-language that follows the colon inside the braces. The general pattern is shown below. You do not need to memorize every option, but understanding the structure will let you look up and apply any specifier you need.

FORMAT SPECIFIER PATTERN
{expression : [fill][align][width][,][.precision][type]}
fill — character used for padding (default is a space). align — < (left), > (right), or ^ (center). width — minimum number of characters for the output. , — adds a thousands separator. .precision — number of digits after the decimal point. type — f (float), d (integer), s (string), % (percentage), e (scientific notation).

Common Type Codes You'll Use

Format specifier type codes most often used in introductory Python courses.
Type CodeMeaningExample ExpressionOutput
fFixed-point floatf"{3.14159:.2f}"3.14
dInteger (decimal)f"{42:05d}"00042
,Thousands separatorf"{1000000:,}"1,000,000
%Percentage (×100)f"{0.875:.1%}"87.5%
eScientific notationf"{6022e20:.2e}"6.02e+23
ROUNDING WITH .Nf
f"{value:.Nf}" → value rounded to N decimal places
Replace N with the number of decimal places you want. For example, :.3f displays three decimal places. Python uses standard rounding (banker's rounding for exact halfway cases).
⚠️ Watch Out!
A common mistake is forgetting the f prefix. Writing "{name}" without the leading f will print the literal text {name} instead of the variable's value. Always double-check that your string starts with f".

Detailed Breakdown — Alignment, Width & Precision

Beyond basic rounding, format specifiers let you control the width (minimum characters), alignment (left, right, or center), and fill character (what fills the extra space). These features are especially useful when you want to create neat, column-aligned tables in the terminal. The diagram below shows how different specifiers change the appearance of the same value.

Five format specifier examples applied to the same value. Notice how adding width, alignment, fill characters, and type codes changes the visual output without changing the underlying number.

In the diagram, each row shows the f-string code on the left and the resulting output on the right. The :.2f specifier rounds to two decimal places, while :>10.2f also pads the output to a minimum width of 10 characters, pushing the number to the right. The star-filled center example (:*^10.2f) demonstrates how a fill character replaces the default spaces. These tools become invaluable when you want to print receipt-style columns or align data neatly.

Worked Example — Building a Mini Receipt

Let's put everything together by writing a small program that prints a formatted receipt for a coffee shop order. We will use variable embedding, rounding, width alignment, and the thousands separator.

Coffee Shop Receipt
1
Step 1 — Define the variablesWe start by assigning the data we need. The item name is a string, the price is a float, and the quantity is an integer. item = "Latte" price = 4.753 (cost per item) qty = 3
2
Step 2 — Compute the subtotalWe can calculate the total directly inside the f-string, but for clarity we also store it: subtotal = price * qty This gives subtotal = 14.259.
subtotal = 14.259
3
Step 3 — Print the item line with alignmentWe want the item name left-aligned in 15 characters and the price right-aligned in 8 characters with two decimal places: print(f"{item:<15}{price:>8.2f}") Here :<15 left-aligns the string in a 15-character field, and :>8.2f right-aligns the float in an 8-character field rounded to 2 decimal places.
Latte 4.75
4
Step 4 — Print the total with roundingNow we display the total, rounded to two decimals: print(f"{'Total':<15}{subtotal:>8.2f}") The raw value 14.259 is automatically rounded to 14.26.
Total 14.26
5
Step 5 — Add a thousands separator for large totalsIf the total were larger — say 12,500.5 — we could add a comma: big = 12500.5 print(f"Grand Total: {big:,.2f}") The comma in the specifier :,.2f inserts the thousands separator automatically.
Grand Total: 12,500.50

f-Strings vs. Older Methods

You may encounter Python code that uses older formatting styles. Understanding the differences helps you read legacy code and appreciate why f-strings are now the recommended approach.

Comparison of Python's three string formatting approaches.
Feature% Operator.format() Methodf-String
Syntax"Hi %s" % name"Hi {}".format(name)f"Hi {name}"
ReadabilityLow — values separated from templateMedium — numbered placeholders helpHigh — variables inline where they appear
Expressions inside?NoLimitedYes — any valid Python expression
SpeedModerateModerateFastest (compiled at parse time)
Python versionAll versions2.6+3.6+
✦ KEY TAKEAWAY
Think of the three methods like giving driving directions. The % operator is like writing the directions on one card and the landmarks on a separate card — you have to match them up manually. The .format() method numbers the landmarks so they're easier to match. An f-string, however, is like a GPS display where the landmark name appears right on the map at the exact spot — no matching required.

Connection to Advanced Formatting

The f-string skills you're learning now form the foundation for more advanced output techniques you'll encounter later. As you progress, you'll find that the same format specifier mini-language powers everything from logging frameworks to data science libraries.

How current f-string skills connect to future Python concepts.
What You Know NowWhat Comes Next
Embedding variables: f"{name}"Using f-strings in logging: logger.info(f"User {name} logged in")
Rounding floats: :.2fCustom __format__ methods on your own classes
Width & alignment: :>10Building ASCII-art tables or using libraries like tabulate
Thousands separator: :,Locale-aware formatting for international number styles
Percentage: :.1%Formatting Pandas DataFrames and Matplotlib axis labels

One exciting feature introduced in Python 3.8 is the self-documenting expression using = inside the braces. Writing f"{score=}" outputs score=95, which is incredibly useful for quick debugging. Keep this trick in your back pocket as you write more complex programs.

Practice Problems

PROBLEM 1 — CONCEPTUAL
Explain, in your own words, what happens when Python encounters the f prefix before a string. Why would "{x + 1}" (without the f) print differently than f"{x + 1}" when x = 5?
PROBLEM 2 — BASIC CALCULATION
Given temp = 98.6731, write an f-string that prints "Temperature: 98.67 °F". Which format specifier rounds to exactly two decimal places?
PROBLEM 3 — INTERMEDIATE
You are printing a table of student names and scores. Each name should be left-aligned in a 20-character field, and each score should be right-aligned in an 8-character field with one decimal place. Write the f-string for one row where name = "Jordan" and score = 87.456. What will the output look like?
PROBLEM 4 — APPLIED
A school fundraiser collected $15237.896 in donations. Write a print statement using an f-string that outputs: "Funds raised: $15,237.90". You need both a thousands separator and rounding. The variable is funds = 15237.896.
PROBLEM 5 — CRITICAL THINKING
A student writes the following code and is confused by the output: grade = 0.894 print(f"You scored {grade:.0%} on the test.") print(f"You scored {grade * 100:.0f}% on the test.") Both lines intend to display the grade as a whole-number percentage. Do they produce the same output? If not, explain what each one prints and why. Which approach would you recommend?

Lesson Summary

f-strings are Python's preferred way to build strings that include variable data. By placing the f-prefix before a string and wrapping any Python expression in curly braces { }, you embed values directly where they will appear in the output. This approach is more readable, faster, and less error-prone than the older % operator or .format() method.

The format specifier after a colon inside the braces gives you precise control over the display. Use :.Nf to round a float to N decimal places, :, to add a thousands separator, :.N% to display a decimal as a percentage, and :>N or :<N to control alignment and width. Mastering these tools lets you produce polished, professional output in any Python program.

Varsity Tutors • Computer Programming 1 (Python) • f-String Formatting