Building dynamic output strings is essential for user messages, reports, and data display. Python provides multiple formatting approaches: legacy %-formatting, the str.format() method, and modern f-strings. Understanding all three helps you read existing code and choose the best tool for each situation.

Old-style formatting (%)

The original C-style formatting using the % operator.

old_style.py
Replay: real traced execution (multi-file project)
# Old-style % formatting

name = "Alice"
age = 30
height = 5.8

# Basic formatting
print("Name: %s" % name)
print("Age: %d" % age)
print("Height: %.1f" % height)

# Multiple values (tuple)
print("Name: %s, Age: %d" % (name, age))

# Format specifiers
print("Integer: %d" % 42)
print("Float: %f" % 3.14159)
print("Scientific: %e" % 1000000)
print("Percentage: %.2f%%" % 95.5)

# Width and precision
print("Padded: %10s" % "test")
print("Number: %05d" % 42)
print("Decimal: %8.2f" % 3.14159)
  1. name ← Alice, age ← 30, height ← 5.8

    3name→ Alice = "Alice"4age→ 30 = 305height→ 5.8 = 5.867# Basic formatting8print("Name: %s" % nameAlice)9print("Age: %d" % age30)10print("Height: %.1f" % height5.8)1112# Multiple values (tuple)13print("Name: %s, Age: %d" % (nameAlice, age30))1415# Format specifiers16print("Integer: %d" % 42)17print("Float: %f" % 3.14159)18print("Scientific: %e" % 1000000)19print("Percentage: %.2f%%" % 95.5)2021# Width and precision22print("Padded: %10s" % "test")23print("Number: %05d" % 42)24print("Decimal: %8.2f" % 3.14159)
    outputName: Alice
    Age: 30
    Height: 5.8
    Name: Alice, Age: 30
    Integer: 42
    Float: 3.141590
    Scientific: 1.000000e+06
    Percentage: 95.50%
    Padded:       test
    Number: 00042
    Decimal:     3.14

Use %s for strings, %d for integers, %f for floats. Pass values as tuple.

old_style_formatting Legacy %-based string formatting using format specifiers like %s and %d.

str.format() method

Flexible formatting with positional and named placeholders.

str_format.py
Replay: real traced execution (multi-file project)
# str.format() method

name = "Bob"
age = 25
balance = 1234.56

# Positional arguments
print("Name: {}, Age: {}".format(name, age))

# Indexed arguments
print("Age: {1}, Name: {0}".format(name, age))

# Named arguments
print("Name: {n}, Age: {a}".format(n=name, a=age))

# Mixed
print("{0} is {1} years old. {0} has ${2:.2f}".format(name, age, balance))

# From dictionary
data = {'name': 'Charlie', 'age': 35}
print("Name: {name}, Age: {age}".format(**data))

# Attribute access
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

person = Person("David", 40)
print("Name: {p.name}, Age: {p.age}".format(p=person))
  1. name ← Bob, age ← 25, balance ← 1234.56, data ← {'name': 'Charlie', 'age': 35}

    3name→ Bob = "Bob"4age→ 25 = 255balance→ 1234.56 = 1234.5667# Positional arguments8print("Name: {}, Age: {}".format(nameBob, age25))910# Indexed arguments11print("Age: {1}, Name: {0}".format(nameBob, age25))1213# Named arguments14print("Name: {n}, Age: {a}".format(n=nameBob, a=age25))1516# Mixed17print("{0} is {1} years old. {0} has ${2:.2f}".format(nameBob, age25, balance1234.56))1819# From dictionary20data→ {'name': 'Charlie', 'age': 35} = {'name': 'Charlie', 'age': 35}21print("Name: {name}, Age: {age}".format(**data{'name': 'Charlie', 'age': 35}))2223# Attribute access24class Person:25    def __init__(self, name, age):26        self.name = name27        self.age = age2829person = Person("David", 40)30print("Name: {p.name}, Age: {p.age}".format(p=person))
    outputName: Bob, Age: 25
    Age: 25, Name: Bob
    Name: Bob, Age: 25
    Bob is 25 years old. Bob has $1234.56
    Name: Charlie, Age: 35
  2. self.name ← David, self.age ← 40

    24class Person:25    def __init__(self⟨Person A⟩, nameDavid, age40):26        self.name→ David = nameDavid27        self.age→ 40 = age40
  3. person ← ⟨Person A⟩

    29person→ ⟨Person A⟩ = Person("David", 40)30print("Name: {p.name}, Age: {p.age}".format(p=person⟨Person A⟩))
    outputName: David, Age: 40

Use {} placeholders with .format(). Supports indexing and named arguments.

str_format The str.format() method with positional and named placeholders.

F-strings (modern)

Inline expressions directly in string literals using f-prefix.

fstring.py
Replay: real traced execution (multi-file project)
# F-strings (formatted string literals)

name = "Eve"
age = 28
balance = 5432.10

# Basic f-string
print(f"Name: {name}, Age: {age}")

# Expressions inside f-strings
print(f"Next year {name} will be {age + 1}")
print(f"Double balance: ${balance * 2:.2f}")

# Method calls
text = "hello world"
print(f"Uppercase: {text.upper()}")
print(f"Title case: {text.title()}")

# Calculations
x, y = 10, 20
print(f"{x} + {y} = {x + y}")
print(f"{x} * {y} = {x * y}")

# Multiple lines
message = (
    f"User Profile:\n"
    f"  Name: {name}\n"
    f"  Age: {age}\n"
    f"  Balance: ${balance:.2f}"
)
print(message)
  1. name ← Eve, age ← 28, balance ← 5432.1, text ← hello world, x ← 10

    3name→ Eve = "Eve"4age→ 28 = 285balance→ 5432.1 = 5432.1067# Basic f-string8print(f"Name: {nameEve}, Age: {age28}")910# Expressions inside f-strings11print(f"Next year {nameEve} will be {age28 + 1}")12print(f"Double balance: ${balance5432.1 * 2:.2f}")1314# Method calls15text→ hello world = "hello world"16print(f"Uppercase: {texthello world.upper()}")17print(f"Title case: {texthello world.title()}")1819# Calculations20x→ 10, y→ 20 = 10, 2021print(f"{x10} + {y20} = {x + y}")22print(f"{x10} * {y20} = {x * y}")2324# Multiple lines25message→ User Profile:
      Name: Eve
      Age: 28
      Balance: $5432.10 = (26    f"User Profile:\n"27    f"  Name: {nameEve}\n"28    f"  Age: {age28}\n"29    f"  Balance: ${balance5432.1:.2f}"30)31print(messageUser Profile:
      Name: Eve
      Age: 28
      Balance: $5432.10)
    outputName: Eve, Age: 28
    Next year Eve will be 29
    Double balance: $10864.20
    Uppercase: HELLO WORLD
    Title case: Hello World
    10 + 20 = 30
    10 * 20 = 200
    User Profile:
      Name: Eve
      Age: 28
      Balance: $5432.10

Prefix string with f, embed expressions in {braces}. Most readable approach.

fstring Formatted string literals with embedded expressions using f-prefix.

Number formatting

Format specifiers for decimal places, separators, and number bases.

num
number_format.py
Replay: real traced execution (multi-file project)
# Number formatting with f-strings

pi = 3.14159265359
num = 1234567

# Decimal places
print(f"Pi: {pi:.2f}")      # 2 decimals
print(f"Pi: {pi:.4f}")      # 4 decimals

# Width and alignment
print(f"Pi: {pi:10.2f}")    # Width 10, 2 decimals
print(f"Pi: {pi:012.2f}")   # Zero-padded

# Thousands separator
print(f"Number: {num:,}")
print(f"Number: {num:_}")   # Underscore separator

# Percentage
ratio = 0.756
print(f"Ratio: {ratio:.1%}")    # 75.6%
print(f"Ratio: {ratio:.2%}")    # 75.60%

# Scientific notation
big_num = 1234567890
print(f"Scientific: {big_num:e}")
print(f"Scientific: {big_num:.2e}")

# Binary, octal, hex
value = 42
print(f"Binary: {value:b}")
print(f"Octal: {value:o}")
print(f"Hex: {value:x}")
print(f"Hex (uppercase): {value:X}")
# Number formatting with f-strings

pi = 3.14159265359
num = 1000

# Decimal places
print(f"Pi: {pi:.2f}")      # 2 decimals
print(f"Pi: {pi:.4f}")      # 4 decimals

# Width and alignment
print(f"Pi: {pi:10.2f}")    # Width 10, 2 decimals
print(f"Pi: {pi:012.2f}")   # Zero-padded

# Thousands separator
print(f"Number: {num:,}")
print(f"Number: {num:_}")   # Underscore separator

# Percentage
ratio = 0.756
print(f"Ratio: {ratio:.1%}")    # 75.6%
print(f"Ratio: {ratio:.2%}")    # 75.60%

# Scientific notation
big_num = 1234567890
print(f"Scientific: {big_num:e}")
print(f"Scientific: {big_num:.2e}")

# Binary, octal, hex
value = 42
print(f"Binary: {value:b}")
print(f"Octal: {value:o}")
print(f"Hex: {value:x}")
print(f"Hex (uppercase): {value:X}")
# Number formatting with f-strings

pi = 3.14159265359
num = 987654321

# Decimal places
print(f"Pi: {pi:.2f}")      # 2 decimals
print(f"Pi: {pi:.4f}")      # 4 decimals

# Width and alignment
print(f"Pi: {pi:10.2f}")    # Width 10, 2 decimals
print(f"Pi: {pi:012.2f}")   # Zero-padded

# Thousands separator
print(f"Number: {num:,}")
print(f"Number: {num:_}")   # Underscore separator

# Percentage
ratio = 0.756
print(f"Ratio: {ratio:.1%}")    # 75.6%
print(f"Ratio: {ratio:.2%}")    # 75.60%

# Scientific notation
big_num = 1234567890
print(f"Scientific: {big_num:e}")
print(f"Scientific: {big_num:.2e}")

# Binary, octal, hex
value = 42
print(f"Binary: {value:b}")
print(f"Octal: {value:o}")
print(f"Hex: {value:x}")
print(f"Hex (uppercase): {value:X}")
  1. pi ← 3.14159265359, num ← 1234567, ratio ← 0.756, big_num ← 1234567890

    3pi→ 3.14159265359 = 3.141592653594num→ 1234567 = 12345675#@num=1000, 98765432167# Decimal places8print(f"Pi: {pi3.14159265359:.2f}")      # 2 decimals9print(f"Pi: {pi3.14159265359:.4f}")      # 4 decimals1011# Width and alignment12print(f"Pi: {pi3.14159265359:10.2f}")    # Width 10, 2 decimals13print(f"Pi: {pi3.14159265359:012.2f}")   # Zero-padded1415# Thousands separator16print(f"Number: {num1234567:,}")17print(f"Number: {num1234567:_}")   # Underscore separator1819# Percentage20ratio→ 0.756 = 0.75621print(f"Ratio: {ratio0.756:.1%}")    # 75.6%22print(f"Ratio: {ratio0.756:.2%}")    # 75.60%2324# Scientific notation25big_num→ 1234567890 = 123456789026print(f"Scientific: {big_num1234567890:e}")27print(f"Scientific: {big_num1234567890:.2e}")2829# Binary, octal, hex30value→ 42 = 4231print(f"Binary: {value42:b}")32print(f"Octal: {value42:o}")33print(f"Hex: {value42:x}")34print(f"Hex (uppercase): {value42:X}")
    outputPi: 3.14
    Pi: 3.1416
    Pi:       3.14
    Pi: 000000003.14
    Number: 1,234,567
    Number: 1_234_567
    Ratio: 75.6%
    Ratio: 75.60%
    Scientific: 1.234568e+09
    Scientific: 1.23e+09
    Binary: 101010
    Octal: 52
    Hex: 2a
    Hex (uppercase): 2A
  1. pi ← 3.14159265359, num ← 1000, ratio ← 0.756, big_num ← 1234567890

    3pi→ 3.14159265359 = 3.141592653594num→ 1000 = 100056# Decimal places7print(f"Pi: {pi3.14159265359:.2f}")      # 2 decimals8print(f"Pi: {pi3.14159265359:.4f}")      # 4 decimals910# Width and alignment11print(f"Pi: {pi3.14159265359:10.2f}")    # Width 10, 2 decimals12print(f"Pi: {pi3.14159265359:012.2f}")   # Zero-padded1314# Thousands separator15print(f"Number: {num1000:,}")16print(f"Number: {num1000:_}")   # Underscore separator1718# Percentage19ratio→ 0.756 = 0.75620print(f"Ratio: {ratio0.756:.1%}")    # 75.6%21print(f"Ratio: {ratio0.756:.2%}")    # 75.60%2223# Scientific notation24big_num→ 1234567890 = 123456789025print(f"Scientific: {big_num1234567890:e}")26print(f"Scientific: {big_num1234567890:.2e}")2728# Binary, octal, hex29value→ 42 = 4230print(f"Binary: {value42:b}")31print(f"Octal: {value42:o}")32print(f"Hex: {value42:x}")33print(f"Hex (uppercase): {value42:X}")
    outputPi: 3.14
    Pi: 3.1416
    Pi:       3.14
    Pi: 000000003.14
    Number: 1,000
    Number: 1_000
    Ratio: 75.6%
    Ratio: 75.60%
    Scientific: 1.234568e+09
    Scientific: 1.23e+09
    Binary: 101010
    Octal: 52
    Hex: 2a
    Hex (uppercase): 2A
  1. pi ← 3.14159265359, num ← 987654321, ratio ← 0.756, big_num ← 1234567890

    3pi→ 3.14159265359 = 3.141592653594num→ 987654321 = 98765432156# Decimal places7print(f"Pi: {pi3.14159265359:.2f}")      # 2 decimals8print(f"Pi: {pi3.14159265359:.4f}")      # 4 decimals910# Width and alignment11print(f"Pi: {pi3.14159265359:10.2f}")    # Width 10, 2 decimals12print(f"Pi: {pi3.14159265359:012.2f}")   # Zero-padded1314# Thousands separator15print(f"Number: {num987654321:,}")16print(f"Number: {num987654321:_}")   # Underscore separator1718# Percentage19ratio→ 0.756 = 0.75620print(f"Ratio: {ratio0.756:.1%}")    # 75.6%21print(f"Ratio: {ratio0.756:.2%}")    # 75.60%2223# Scientific notation24big_num→ 1234567890 = 123456789025print(f"Scientific: {big_num1234567890:e}")26print(f"Scientific: {big_num1234567890:.2e}")2728# Binary, octal, hex29value→ 42 = 4230print(f"Binary: {value42:b}")31print(f"Octal: {value42:o}")32print(f"Hex: {value42:x}")33print(f"Hex (uppercase): {value42:X}")
    outputPi: 3.14
    Pi: 3.1416
    Pi:       3.14
    Pi: 000000003.14
    Number: 987,654,321
    Number: 987_654_321
    Ratio: 75.6%
    Ratio: 75.60%
    Scientific: 1.234568e+09
    Scientific: 1.23e+09
    Binary: 101010
    Octal: 52
    Hex: 2a
    Hex (uppercase): 2A

Use :.2f for decimals, :, for thousands, :b/:x/:o for binary/hex/octal.

number_format Format specifiers for decimal places, thousands separators, and number bases.

Alignment and padding

Control width, alignment, and fill characters for formatted output.

alignment.py
Replay: real traced execution (multi-file project)
# String alignment and padding

text = "Python"
num = 42

# Left align (default for strings)
print(f"'{text:<15}'")

# Right align (default for numbers)
print(f"'{text:>15}'")

# Center align
print(f"'{text:^15}'")

# Custom fill character
print(f"'{text:*<15}'")
print(f"'{text:->15}'")
print(f"'{text:=^15}'")

# Number alignment
print(f"'{num:<10}'")
print(f"'{num:>10}'")
print(f"'{num:^10}'")

# Table formatting
print("\nTable Example:")
print(f"{'Name':<12} {'Age':>5} {'Balance':>10}")
print(f"{'-'*12} {'-'*5} {'-'*10}")
print(f"{'Alice':<12} {30:>5} {1234.56:>10.2f}")
print(f"{'Bob':<12} {25:>5} {987.65:>10.2f}")
print(f"{'Charlie':<12} {35:>5} {5432.10:>10.2f}")
  1. text ← Python, num ← 42

    3text→ Python = "Python"4num→ 42 = 4256# Left align (default for strings)7print(f"'{textPython:<15}'")89# Right align (default for numbers)10print(f"'{textPython:>15}'")1112# Center align13print(f"'{textPython:^15}'")1415# Custom fill character16print(f"'{textPython:*<15}'")17print(f"'{textPython:->15}'")18print(f"'{textPython:=^15}'")1920# Number alignment21print(f"'{num42:<10}'")22print(f"'{num42:>10}'")23print(f"'{num42:^10}'")2425# Table formatting26print("\nTable Example:")27print(f"{'Name':<12} {'Age':>5} {'Balance':>10}")28print(f"{'-'*12} {'-'*5} {'-'*10}")29print(f"{'Alice':<12} {30:>5} {1234.56:>10.2f}")30print(f"{'Bob':<12} {25:>5} {987.65:>10.2f}")31print(f"{'Charlie':<12} {35:>5} {5432.10:>10.2f}")
    output'Python         '
    '         Python'
    '    Python     '
    'Python*********'
    '---------Python'
    '====Python====='
    '42        '
    '        42'
    '    42    '
    
    Table Example:
    Name           Age    Balance
    ------------ ----- ----------
    Alice           30    1234.56
    Bob             25     987.65
    Charlie         35    5432.10

Use < left, > right, ^ center. Add fill character before alignment.

alignment Width, alignment, and fill characters for formatted output.

Practical example

Combine formatting techniques to build formatted reports.

practical.py
Replay: real traced execution (multi-file project)
# Practical example: Report generation

from datetime import datetime

class Transaction:
    def __init__(self, date, description, amount):
        self.date = date
        self.description = description
        self.amount = amount

# Sample data
transactions = [
    Transaction(datetime(2026, 1, 15), "Grocery Store", -45.67),
    Transaction(datetime(2026, 1, 18), "Salary Deposit", 2500.00),
    Transaction(datetime(2026, 1, 20), "Electric Bill", -87.50),
    Transaction(datetime(2026, 1, 22), "Restaurant", -32.40),
    Transaction(datetime(2026, 1, 25), "Online Purchase", -156.89),
]

# Generate report
print("=" * 70)
print(f"{'BANK STATEMENT':^70}")
print("=" * 70)
print()

print(f"{'Date':<12} {'Description':<25} {'Amount':>15}")
print("-" * 70)

balance = 1000.00
for txn in transactions:
    balance += txn.amount
    date_str = txn.date.strftime("%Y-%m-%d")

    # Color-code positive/negative (using symbols)
    sign = "+" if txn.amount >= 0 else "-"
    amount_str = f"{sign}${abs(txn.amount):.2f}"

    print(f"{date_str:<12} {txn.description:<25} {amount_str:>15}")

print("-" * 70)
print(f"{'FINAL BALANCE:':<37} ${balance:>15,.2f}")
print("=" * 70)

# Summary statistics
total_deposits = sum(t.amount for t in transactions if t.amount > 0)
total_withdrawals = sum(t.amount for t in transactions if t.amount < 0)

print()
print("SUMMARY")
print(f"  Total Deposits:    ${total_deposits:>10,.2f}")
print(f"  Total Withdrawals: ${abs(total_withdrawals):>10,.2f}")
print(f"  Net Change:        ${total_deposits + total_withdrawals:>10,.2f}")
  1. transactions = [

    11# Sample data12transactions = [13    Transaction(datetime(2026, 1, 15), "Grocery Store", -45.67),14    Transaction(datetime(2026, 1, 18), "Salary Deposit", 2500.00),15    Transaction(datetime(2026, 1, 20), "Electric Bill", -87.50),16    Transaction(datetime(2026, 1, 22), "Restaurant", -32.40),17    Transaction(datetime(2026, 1, 25), "Online Purchase", -156.89),18]
  2. self.date ← 2026-01-15 00:00:00, self.description ← Grocery Store

    pass 1 of 5
    5class Transaction:6    def __init__(self⟨Transaction A⟩, date2026-01-15 00:00:00, descriptionGrocery Store, amount-45.67):7        self.date→ 2026-01-15 00:00:00 = date2026-01-15 00:00:008        self.description→ Grocery Store = descriptionGrocery Store9        self.amount→ -45.67 = amount-45.67
    All 5 passes — pass 1 is the card above
    passselfdatedescriptionamountself.dateself.descriptionself.amount
    1⟨Transaction A⟩2026-01-15 00:00:00Grocery Store-45.672026-01-15 00:00:00Grocery Store-45.67
    2⟨Transaction B⟩2026-01-18 00:00:00Salary Deposit2500.02026-01-18 00:00:00Salary Deposit2500.0
    3⟨Transaction C⟩2026-01-20 00:00:00Electric Bill-87.52026-01-20 00:00:00Electric Bill-87.5
    4⟨Transaction D⟩2026-01-22 00:00:00Restaurant-32.42026-01-22 00:00:00Restaurant-32.4
    5⟨Transaction E⟩2026-01-25 00:00:00Online Purchase-156.892026-01-25 00:00:00Online Purchase-156.89
  3. transactions ← [⟨Transaction A⟩, ⟨Transaction B⟩, ⟨Transaction C⟩, ⟨Transaction D⟩, ⟨Transaction E⟩]

    11# Sample data12transactions→ [⟨Transaction A⟩, ⟨Transaction B⟩, ⟨Transaction C⟩, ⟨Transaction D⟩, ⟨Transaction E⟩] = [13    Transaction(datetime(2026, 1, 15), "Grocery Store", -45.67),14    Transaction(datetime(2026, 1, 18), "Salary Deposit", 2500.00),15    Transaction(datetime(2026, 1, 20), "Electric Bill", -87.50),16    Transaction(datetime(2026, 1, 22), "Restaurant", -32.40),17    Transaction(datetime(2026, 1, 25), "Online Purchase", -156.89),18]1920# Generate report21print("=" * 70)22print(f"{'BANK STATEMENT':^70}")23print("=" * 70)24print()2526print(f"{'Date':<12} {'Description':<25} {'Amount':>15}")27print("-" * 70)2829balance→ 1000.0 = 1000.0030for txn in transactions:
    output======================================================================
                                BANK STATEMENT
    ======================================================================
    Date         Description                        Amount
    ----------------------------------------------------------------------
  4. balance ← 954.33, date_str ← 2026-01-15, sign ← -, amount_str ← -$45.67

    pass 1 of 5
    29balance = 1000.0030for txn⟨Transaction A⟩ in transactions[⟨Transaction A⟩, ⟨Transaction B⟩, ⟨Transaction C⟩, ⟨Transaction D⟩, ⟨Transaction E⟩]:31    balance→ 954.33 += txn.amount-45.6732    date_str→ 2026-01-15 = txn.date2026-01-15 00:00:00.strftime("%Y-%m-%d")33    34    # Color-code positive/negative (using symbols)35    sign→ - = "+" if txn.amount-45.67 >= 0 else "-"36    amount_str→ -$45.67 = f"{sign-}${abs(txn.amount-45.67):.2f}"37    38    print(f"{date_str2026-01-15:<12} {txn.descriptionGrocery Store:<25} {amount_str-$45.67:>15}")
    output2026-01-15   Grocery Store                     -$45.67
    All 5 passes — pass 1 is the card above
    passtxntxn.amounttxn.datetxn.descriptionbalancedate_strsignamount_str
    1⟨Transaction A⟩-45.672026-01-15 00:00:00Grocery Store1000.0 954.332026-01-15--$45.67
    2⟨Transaction B⟩2500.02026-01-18 00:00:00Salary Deposit954.33 3454.332026-01-18++$2500.00
    3⟨Transaction C⟩-87.52026-01-20 00:00:00Electric Bill3454.33 3366.832026-01-20--$87.50
    4⟨Transaction D⟩-32.42026-01-22 00:00:00Restaurant3366.83 3334.432026-01-22--$32.40
    5⟨Transaction E⟩-156.892026-01-25 00:00:00Online Purchase3334.43 3177.542026-01-25--$156.89
  5. total_deposits ← 2500.0, total_withdrawals ← -322.46

    40print("-" * 70)41print(f"{'FINAL BALANCE:':<37} ${balance3177.54:>15,.2f}")42print("=" * 70)4344# Summary statistics45total_deposits→ 2500.0 = sum(t.amount(empty) for t in transactions[⟨Transaction A⟩, ⟨Transaction B⟩, ⟨Transaction C⟩, ⟨Transaction D⟩, ⟨Transaction E⟩] if t.amount > 0)46total_withdrawals→ -322.46 = sum(t.amount(empty) for t in transactions[⟨Transaction A⟩, ⟨Transaction B⟩, ⟨Transaction C⟩, ⟨Transaction D⟩, ⟨Transaction E⟩] if t.amount < 0)4748print()49print("SUMMARY")50print(f"  Total Deposits:    ${total_deposits2500.0:>10,.2f}")51print(f"  Total Withdrawals: ${abs(total_withdrawals-322.46):>10,.2f}")52print(f"  Net Change:        ${total_deposits2500.0 + total_withdrawals-322.46:>10,.2f}")
    output----------------------------------------------------------------------
    FINAL BALANCE:                        $       3,177.54
    ======================================================================
    SUMMARY
      Total Deposits:    $  2,500.00
      Total Withdrawals: $    322.46
      Net Change:        $  2,177.54

Exercise: practical.py

Create a formatted receipt with aligned columns, currency formatting, and totals