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.

A Python coding terminal with a program flow and laptop.
Inside this lesson 10 sections 5 questions 7 figures

SECTION 1

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.

SECTION 2

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.

SECTION 3

Visual Explanation — Anatomy of an f-String

Anatomy of an f-Stringf"Total: {price * qty:.2f} dollars"f-prefixActivates formattingLiteral Text"Total: " and " dollars"Expressionprice * qty → evaluatedFormat Specifier.2f → 2 decimal placesCurly Braces { }Delimit the expression slotOutput →Total: 29.94 dollars(if price=9.98, qty=3)
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.

SECTION 4

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]{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

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

Format specifier type codes most often used in introductory Python courses.

ROUNDING WITH .Nf

f"value:.Nf"→valueroundedtoNdecimalplacesf"{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".

SECTION 5

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.

Format Specifier Showcase — value = 3.14159Defaultf"{value}"Output:3.14159Round to 2 decimalsf"{value:.2f}"Output:3.14Width 10, right-alignedf"{value:>10.2f}"Output: 3.14Center, star-filledf"{value:*^10.2f}"Output:***3.14***Percentagef"{0.875:.1%}"Output:87.5%
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.

SECTION 6

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. 1

    Step 1 — Define the variables

    We 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. 2

    Step 2 — Compute the subtotal

    We 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. 3

    Step 3 — Print the item line with alignment

    We 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. 4

    Step 4 — Print the total with rounding

    Now 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. 5

    Step 5 — Add a thousands separator for large totals

    If 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

SECTION 7

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.

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+

Comparison of Python's three string formatting approaches.

✦

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.

SECTION 8

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.

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

How current f-string skills connect to future Python concepts.

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.

SECTION 9

Practice Problems

Question 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?
Show answer
The f prefix tells Python to treat the string as a formatted string literal. Python scans the string for curly braces, evaluates the expression inside each pair, and replaces the braces with the result. Without the f prefix, "{x + 1}" is a regular string, so the output is the literal text {x + 1}. With the f prefix, Python evaluates x + 1 (which is 6) and produces the output 6.

Question 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?
Show answer
The correct f-string is f"Temperature: {temp:.2f} °F". The format specifier :.2f tells Python to format the value as a fixed-point float with exactly 2 digits after the decimal point. Python rounds 98.6731 to 98.67 and inserts it into the string. The f type code stands for fixed-point notation.

Question 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?
Show answer
The f-string is f"{name:<20}{score:>8.1f}". The specifier :<20 left-aligns the name in a field 20 characters wide, padding with spaces on the right. The specifier :>8.1f right-aligns the score in an 8-character field, rounded to one decimal place. The output is Jordan 87.5. The 14 extra spaces after 'Jordan' fill the 20-character name field, and the score is padded with spaces on the left to fill 8 characters.

Question 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.
Show answer
The statement is print(f"Funds raised: ${funds:,.2f}"). The format specifier :,.2f combines two features: the comma , inserts a thousands separator (turning 15237 into 15,237), and .2f rounds to two decimal places (turning .896 into .90). The dollar sign is literal text outside the braces, so it appears directly before the number. This is a common pattern for displaying currency values.

Question 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?
Show answer
Both lines produce the output You scored 89% on the test. — the results happen to be the same for this particular value, but the mechanisms differ. In the first line, the % type code automatically multiplies the value by 100 and appends a percent sign, so .0% means 'zero decimal places, shown as a percentage.' In the second line, the student manually multiplies by 100 and uses .0f to round, then adds a literal % character. The first approach is recommended because it is shorter, less error-prone, and clearly communicates the intent. If the student ever wants decimals, changing .0% to .1% is simpler than adjusting a manual multiplication.

SUMMARY

Lesson Summary

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