Python String Formatting
Note: This post is based on my old programming study notes when I taught myself.
String Formatting
After understanding data types in Python, it is important to know how to format them properly.
Method 1: Old formatting using %
%d
: integer%s
: string%f
: float%c
: character
number = 3
day = "several"
y = 'I ate %d apples. So I was happy for %s days.' % (number, day)
print(y)
# Output: I ate 3 apples. So I was happy for several days.
Method 2: Using {}
with .format()
Case 1: Direct way
x = "I like {} very much".format('coding')
print(x)
# Output: I like coding very much
Case 2: Using variables inside string
x = 'I like {name} very much'.format(name="Python")
print(x)
# Output: I like Python very much
Advanced .format() usage:
# Multiple variables
text = "My name is {name} and I am {age} years old".format(name="Alice", age=25)
# Positional arguments
text = "The {0} is {1} years old".format("cat", 5)
# Number formatting
price = 49.95
text = "The price is {:.2f}".format(price) # Output: The price is 49.95
Method 3: Using f-strings (Python 3.6+)
name = 'Elon Musk'
age = 52
z = f"This is {name}."
print(z)
# Output: This is Elon Musk.
# More examples
greeting = f"Hello, {name}! You are {age} years old."
calculation = f"2 + 3 = {2 + 3}"
formatted_number = f"Pi is approximately {3.14159:.2f}"
Escape Characters
Escape characters allow you to include special characters in strings that would otherwise be difficult to represent.
Common Escape Characters
- Double quote:
\"
- Single quote:
\'
- Backslash:
\\
- Newline:
\n
- Tab:
\t
- Carriage return:
\r
Examples
# Including quotes in strings
text1 = "He said, \"Hello World!\""
text2 = 'It\'s a beautiful day'
# Backslash in path
path = "C:\\Users\\Documents\\file.txt"
# Multi-line strings with newline
message = "First line\nSecond line\nThird line"
# Tab spacing
table = "Name\tAge\tCity"
Raw Strings
Use raw strings (prefix with r
) to avoid interpreting escape characters:
# Regular string with escape characters
path1 = "C:\\Users\\Documents"
# Raw string - backslashes are treated literally
path2 = r"C:\Users\Documents"
# Both produce the same result but raw strings are cleaner for paths
Quick Reference
Method | Syntax | Example | Best Use Case |
---|---|---|---|
% formatting | "text %s" % value | "Hello %s" % name | Legacy code |
.format() | "text {}".format(value) | "Hello {}".format(name) | Python 2.7+ compatibility |
f-strings | f"text {value}" | f"Hello {name}" | Modern Python (3.6+) - Recommended |
Recommendation: Use f-strings for new code as they are more readable, faster, and less error-prone.
Technical Interview Essentials
Advanced f-string Techniques
1. Expression Evaluation
# Mathematical expressions
radius = 5
area = f"Circle area: {3.14159 * radius**2:.2f}" # "Circle area: 78.54"
# Function calls
def get_user_name():
return "Alice"
greeting = f"Hello, {get_user_name()}" # "Hello, Alice"
# Method chaining
text = "python programming"
formatted = f"Title: {text.title().replace(' ', '-')}" # "Title: Python-Programming"
2. Conditional Formatting
score = 85
grade = f"Grade: {'Pass' if score >= 60 else 'Fail'}" # "Grade: Pass"
# Complex conditions
status = "active"
count = 42
message = f"User is {status} with {count} {'item' if count == 1 else 'items'}"
3. Format Specifiers for Numbers
number = 12345.6789
# Decimal places
formatted = f"{number:.2f}" # "12345.68"
# Padding and alignment
formatted = f"{number:>10.2f}" # " 12345.68" (right-aligned)
formatted = f"{number:<10.2f}" # "12345.68 " (left-aligned)
formatted = f"{number:^10.2f}" # " 12345.68 " (center-aligned)
# Zero padding
formatted = f"{number:010.2f}" # "0012345.68"
# Thousands separator
formatted = f"{number:,.2f}" # "12,345.68"
# Percentage
ratio = 0.85
formatted = f"{ratio:.1%}" # "85.0%"
# Scientific notation
large_num = 1234567890
formatted = f"{large_num:.2e}" # "1.23e+09"
4. Date and Time Formatting
from datetime import datetime
now = datetime.now()
# Various date formats
date_str = f"Today is {now:%Y-%m-%d}" # "Today is 2025-07-15"
time_str = f"Current time: {now:%H:%M:%S}" # "Current time: 14:30:45"
full_str = f"Full: {now:%A, %B %d, %Y}" # "Full: Tuesday, July 15, 2025"
Performance Comparison (Interview Knowledge)
import timeit
name = "Python"
age = 10
# Performance test - f-strings are fastest!
def test_percent():
return "Hello %s, you are %d years old" % (name, age)
def test_format():
return "Hello {}, you are {} years old".format(name, age)
def test_fstring():
return f"Hello {name}, you are {age} years old"
# f-strings are typically 2-3x faster than .format() and % formatting
Common Interview Patterns
1. Build Dynamic Strings
def build_sql_query(table, conditions):
"""Build SQL WHERE clause dynamically - common interview question"""
where_parts = []
for key, value in conditions.items():
if isinstance(value, str):
where_parts.append(f"{key} = '{value}'")
else:
where_parts.append(f"{key} = {value}")
where_clause = " AND ".join(where_parts)
return f"SELECT * FROM {table} WHERE {where_clause}"
# Usage
conditions = {"name": "Alice", "age": 25, "status": "active"}
query = build_sql_query("users", conditions)
print(query)
# SELECT * FROM users WHERE name = 'Alice' AND age = 25 AND status = 'active'
2. Format Data for Display
def format_user_table(users):
"""Format user data in table - common formatting task"""
if not users:
return "No users found."
# Calculate column widths
name_width = max(len(user['name']) for user in users)
email_width = max(len(user['email']) for user in users)
# Header
header = f"{'Name':<{name_width}} | {'Email':<{email_width}} | {'Age':>3}"
separator = "-" * len(header)
# Build table
lines = [header, separator]
for user in users:
line = f"{user['name']:<{name_width}} | {user['email']:<{email_width}} | {user['age']:>3}"
lines.append(line)
return "\n".join(lines)
# Test data
users = [
{"name": "Alice Smith", "email": "alice@example.com", "age": 25},
{"name": "Bob", "email": "bob@test.com", "age": 30},
{"name": "Charlie Brown", "email": "charlie@demo.org", "age": 35}
]
print(format_user_table(users))
3. Parse and Format Log Entries
from datetime import datetime
def format_log_entry(level, message, timestamp=None):
"""Format log entry - practical programming task"""
if timestamp is None:
timestamp = datetime.now()
# Color codes for different levels (useful for terminal output)
colors = {
"ERROR": "\033[91m", # Red
"WARNING": "\033[93m", # Yellow
"INFO": "\033[92m", # Green
"DEBUG": "\033[94m", # Blue
}
reset_color = "\033[0m"
color = colors.get(level.upper(), "")
formatted_time = timestamp.strftime("%Y-%m-%d %H:%M:%S")
return f"[{formatted_time}] {color}{level.upper():<7}{reset_color} | {message}"
# Usage
print(format_log_entry("error", "Database connection failed"))
print(format_log_entry("info", "User logged in successfully"))
print(format_log_entry("warning", "Low disk space detected"))
String Validation & Sanitization
1. Input Validation
def validate_and_format_phone(phone):
"""Clean and validate phone number - common validation task"""
# Remove all non-digit characters
digits = ''.join(c for c in phone if c.isdigit())
if len(digits) == 10:
# Format as (XXX) XXX-XXXX
return f"({digits[:3]}) {digits[3:6]}-{digits[6:]}"
elif len(digits) == 11 and digits[0] == '1':
# Handle +1 country code
return f"+1 ({digits[1:4]}) {digits[4:7]}-{digits[7:]}"
else:
return f"Invalid phone number: {phone}"
# Test cases
test_phones = ["1234567890", "123-456-7890", "(123) 456-7890", "1-123-456-7890"]
for phone in test_phones:
print(f"{phone:<15} -> {validate_and_format_phone(phone)}")
2. Safe String Building (SQL Injection Prevention)
def safe_user_query(user_id, table="users"):
"""Demonstrate parameterized queries - security interview topic"""
# WRONG - SQL injection vulnerable
# Don't do: f"SELECT * FROM {table} WHERE id = {user_id}"
# RIGHT - Use parameterized queries in real code
# This is just for demonstration of string safety
if not isinstance(user_id, int) or user_id <= 0:
raise ValueError("User ID must be positive integer")
if not table.replace('_', '').isalnum():
raise ValueError("Invalid table name")
return f"SELECT * FROM {table} WHERE id = ?" # Placeholder for real parameterization
# Safe formatting for display/logging (not database queries)
def format_search_results(query_term, results_count):
"""Safe formatting for user input display"""
# Escape special characters for display
safe_term = query_term.replace('<', '<').replace('>', '>')
return f"Found {results_count} results for '{safe_term}'"
Common Interview Gotchas
1. Late Binding with f-strings
# Interview trap - variable evaluation timing
functions = []
# WRONG - all functions will use the final value of i
for i in range(3):
functions.append(lambda: f"Value is {i}")
for func in functions:
print(func()) # All print "Value is 2"!
# CORRECT - capture the value at definition time
functions = []
for i in range(3):
functions.append(lambda x=i: f"Value is {x}")
for func in functions:
print(func()) # Prints "Value is 0", "Value is 1", "Value is 2"
2. Float Precision Issues
# Interview knowledge - floating point precision
value = 0.1 + 0.2
print(f"0.1 + 0.2 = {value}") # "0.1 + 0.2 = 0.30000000000000004"
print(f"0.1 + 0.2 = {value:.1f}") # "0.1 + 0.2 = 0.3" (rounded)
# For financial calculations, use Decimal
from decimal import Decimal
precise_value = Decimal('0.1') + Decimal('0.2')
print(f"Precise: {precise_value}") # "Precise: 0.3"
3. Memory Efficiency
# For large-scale string operations, be memory conscious
def efficient_string_join(items):
"""Memory-efficient string concatenation"""
# WRONG - O(n²) time complexity due to string immutability
# result = ""
# for item in items:
# result += f"{item}, "
# RIGHT - O(n) time complexity
formatted_items = [f"{item}" for item in items]
return ", ".join(formatted_items)
# For very large datasets, consider generators
def format_large_dataset(data_generator):
"""Format large dataset without loading all into memory"""
for item in data_generator:
yield f"Processed: {item['name']} at {item['timestamp']}"