Post

Python - String Formatting

Python - String Formatting

What is String Formatting in Python?

String formatting is the process of creating strings with dynamic content by incorporating variables, expressions, or values within a string literal. It allows you to build complex strings by inserting values at specific positions.

Basic Example

1
2
3
4
5
6
7
8
x = 10
y = 20
s = x + y

# Using comma separation (simplest but limited)
print("The first number is", x, "the second number is", y, "Sum is", s)

# Output: The first number is 10 the second number is 20 Sum is 30

String Formatting Methods in Python

Python provides several methods for string formatting:

1. Old-Style % Operator (Python 2+)

The oldest method, inspired by C’s printf() function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
name = "Alice"
age = 25
balance = 1234.567

# Single value
print("Hello, %s!" % name)  # Hello, Alice!

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

# Dictionary interpolation
person = {"name": "Alice", "age": 25}
print("Hello, %(name)s! You're %(age)d years old." % person)

# Number formatting
print("Balance: $%.2f" % balance)  # Balance: $1234.57
print("Hex: %x" % 255)  # Hex: ff
print("Octal: %o" % 64)  # Octal: 100

Format Specifiers for % operator:

  • %s - String
  • %d or %i - Decimal integer
  • %f - Floating-point number
  • %.2f - Floating-point with 2 decimal places
  • %x - Hexadecimal (lowercase)
  • %X - Hexadecimal (uppercase)
  • %o - Octal
  • %e - Scientific notation

2. str.format() Method (Python 3+)

A more flexible and readable approach.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
name = "Alice"
age = 25
balance = 1234.567

# Positional arguments
print("Hello, {}! You're {} years old.".format(name, age))

# Indexed arguments
print("Hello, {1}! You're {0} years old.".format(age, name))

# Named arguments
print("Hello, {name}! You're {age} years old.".format(name=name, age=age))

# Dictionary unpacking
person = {"name": "Alice", "age": 25}
print("Hello, {name}! You're {age} years old.".format(**person))

# Number formatting
print("Balance: ${:.2f}".format(balance))  # Balance: $1234.57
print("Comma separator: {:,}".format(1234567890))  # 1,234,567,890

# Alignment and padding
print("{:<10}".format("left"))   # left      
print("{:>10}".format("right"))  #      right
print("{:^10}".format("center")) #   center   
print("{:*^10}".format("center"))# ***center***

Format Specification Mini-Language:

  • {:d} - Decimal integer
  • {:f} - Floating-point (default 6 decimals)
  • {:.2f} - Floating-point with 2 decimals
  • {:>10} - Right-aligned in 10 chars
  • {:<10} - Left-aligned in 10 chars
  • {:^10} - Centered in 10 chars
  • {:+f} - Show sign for both positive and negative
  • {: } - Space for positive, minus for negative

The most modern, readable, and performant method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
name = "Alice"
age = 25
balance = 1234.567

# Basic interpolation
print(f"Hello, {name}! You're {age} years old.")

# Expressions in f-strings
print(f"Next year you'll be {age + 1}")

# Function calls
print(f"Name in uppercase: {name.upper()}")

# Conditional expressions
print(f"Result: {'Even' if age % 2 == 0 else 'Odd'}")

# Number formatting
print(f"Balance: ${balance:.2f}")  # Balance: $1234.57
print(f"Comma separator: {1234567890:,}")  # 1,234,567,890

# Alignment and padding
print(f"{'left':<10}")   # left      
print(f"{'right':>10}")  #      right
print(f"{'center':^10}") #   center   

# Self-documenting (Python 3.8+)
value = 42
print(f"{value=}")  # value=42

# Debugging example
x, y = 10, 20
print(f"x={x}, y={y}, sum={x+y}")  # x=10, y=20, sum=30

F-String Conversion Flags:

  • {variable!s} - Calls str() on the variable
  • {variable!r} - Calls repr() on the variable
  • {variable!a} - Calls ascii() on the variable
1
2
3
4
5
6
7
8
9
10
11
12
13
class Person:
    def __init__(self, name):
        self.name = name
    
    def __str__(self):
        return f"Person named {self.name}"
    
    def __repr__(self):
        return f"Person('{self.name}')"

p = Person("Alice")
print(f"{p!s}")  # Person named Alice
print(f"{p!r}")  # Person('Alice')

Advanced F-String Features (Python 3.12+)

Quotation Mark Reuse

1
2
3
person = {"name": "Alice", "age": 25}
# Python 3.12 allows reusing quotes in embedded expressions
print(f"Hello, {person["name"]}! You're {person['age']} years old.")

Backslash Support

1
2
3
4
words = ["Hello", "World"]
print(f"{'\n'.join(words)}")
# Hello
# World

Inline Comments

1
2
data = {"value": 42}
result = f"Value: {data['value']  # Get the value from dictionary}"

Performance Comparison

F-strings are generally faster than other methods:

MethodExecution Time (1M iterations)
F-string~87 ms
% operator~91 ms
str.format()~145 ms
1
2
3
4
5
6
7
8
import timeit

name = "Jane"
age = 25

print("F-string:", timeit.timeit(f"f'Hello, {name}! You're {age} years old.'", number=1000000))
print("% operator:", timeit.timeit("'Hello, %s! You're %s years old.' % (name, age)", number=1000000))
print("str.format():", timeit.timeit("'Hello, {}! You're {} years old.'.format(name, age)", number=1000000))

When to Use Each Method

MethodBest For
F-stringsPython 3.6+, most cases, especially with expressions and debugging
str.format()Pre-Python 3.6 code, internationalization (templates), complex formatting
% operatorSimple cases, legacy code, logging (lazy evaluation)

Special Cases

  1. Logging - Use % for lazy evaluation:
    1
    2
    
    import logging
    logging.warning("Error: %s", error_message)  # Only formats if warning level is enabled
    
  2. SQL Queries - Never use string formatting directly! Use parameterized queries:
    1
    2
    
    # BAD: cursor.execute(f"SELECT * FROM users WHERE name = '{name}'")
    # GOOD: cursor.execute("SELECT * FROM users WHERE name = %s", (name,))
    
  3. Internationalization - Use str.format() with templates:
    1
    2
    
    greeting_template = "{greeting} Pythonista!"
    print(greeting_template.format(greeting="Good Morning"))
    

Common Formatting Examples

Numbers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Decimal, binary, octal, hexadecimal
num = 42
print(f"Decimal: {num:d}")
print(f"Binary: {num:b}")    # 101010
print(f"Octal: {num:o}")     # 52
print(f"Hex: {num:x}")       # 2a

# Floating-point formatting
pi = 3.14159265
print(f"2 decimals: {pi:.2f}")    # 3.14
print(f"Scientific: {pi:e}")      # 3.14e+00
print(f"Percentage: {0.856:%}")   # 85.600000%

# Sign display
print(f"Positive: {+42:+f}")  # +42.000000
print(f"Negative: {-42:-f}")  # -42.000000

Strings

1
2
3
4
5
6
7
8
text = "Hello"
print(f"Left aligned: '{text:<10}'")   # 'Hello     '
print(f"Right aligned: '{text:>10}'")  # '     Hello'
print(f"Centered: '{text:^10}'")       # '  Hello   '

# Truncation
long_text = "Hello World"
print(f"{long_text:.5}")  # Hello

Dates and Times

1
2
3
4
5
6
7
8
9
from datetime import datetime

now = datetime.now()
print(f"Date: {now:%Y-%m-%d}")
print(f"Time: {now:%H:%M:%S}")
print(f"Full: {now:%Y-%m-%d %H:%M:%S}")

# Custom format
print(f"{now:%A, %B %d, %Y}")  # Wednesday, June 25, 2026

Nested F-Strings (Python 3.12+)

1
2
3
width = 10
value = 42
print(f"Value: {value:{width}d}")  # Value:         42

Best Practices

  1. Use f-strings for Python 3.6+ - They’re the most readable and performant
  2. Group related formatting - Keep format specifiers consistent
  3. Use descriptive variable names - Makes code self-documenting
  4. Avoid import * with string modules - Use explicit imports
  5. Consider locale for international apps - Use locale.format() for user-facing numbers

Conclusion

Python provides multiple ways to format strings, each with its own advantages:

  • F-strings are the modern standard (Python 3.6+)
  • str.format() offers flexibility and works in older Python versions
  • % operator is legacy but still useful for specific cases like logging

Choose the method that best fits your Python version, readability needs, and performance requirements. For new code, f-strings are generally the best choice due to their clarity, speed, and feature-rich syntax.

This post is licensed under CC BY 4.0 by the author.