String Formatting and I/O

The Glue Between Computation and Communication

Scientific computing is not just about running algorithms — it is about communicating results. You need to format numbers in scientific notation for log files, generate filenames from parameter sweeps, read configuration from YAML files, and write results to CSV for further analysis. Python's f-strings and I/O libraries make this seamless when used correctly.

Definition:

f-Strings with Format Specs

f-strings (formatted string literals, Python 3.6+) embed expressions inside {} with optional format specifications:

snr_db = 15.3456789
ber = 1.23e-5
n_antennas = 4

# Scientific notation
print(f"BER = {ber:.2e}")            # BER = 1.23e-05

# Fixed-point with units
print(f"SNR = {snr_db:.1f} dB")      # SNR = 15.3 dB

# Padding and alignment
print(f"{'Method':<15} {'BER':>10}")  # Left/right alignment
print(f"{'MMSE':<15} {ber:>10.2e}")

# Thousands separator
n_samples = 1_000_000
print(f"Samples: {n_samples:,}")      # Samples: 1,000,000

# Shape inspection (invaluable for debugging)
import numpy as np
H = np.random.randn(4, 2)
print(f"H shape: {H.shape}, dtype: {H.dtype}")

Definition:

Common Format Specifications

The format spec mini-language after the colon in {value:spec}:

Spec Meaning Example
.2f 2 decimal places 3.14
.4e Scientific notation, 4 decimals 1.2346e+02
.3g General format (auto-choose f/e) 123 or 1.23e+05
>10 Right-align in 10 chars SNR
<10 Left-align in 10 chars SNR
^10 Center in 10 chars SNR
, Thousands separator 1,000,000
+ Always show sign +3.14
08d Zero-padded integer (8 digits) 00000042

Definition:

Logging vs. Print Statements

Use the logging module instead of print() for anything beyond quick debugging:

import logging

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s [%(levelname)s] %(message)s',
    datefmt='%H:%M:%S',
)
logger = logging.getLogger(__name__)

logger.info(f"Starting simulation: SNR={snr_db:.1f} dB, Nt={n_antennas}")
logger.debug(f"Channel matrix shape: {H.shape}")
logger.warning(f"BER={ber:.2e} below threshold — results may be unreliable")

Logging provides timestamps, severity levels, module names, and can be redirected to files without modifying any code.

f-string

A formatted string literal (Python 3.6+) that embeds expressions inside {} within a string prefixed by f. Supports format specifications for controlling number display.

Example: Formatting a Results Table

Given simulation results as a list of dictionaries, print a formatted table with aligned columns and proper number formatting.

Example: Reading and Writing Scientific Data Files

Read simulation parameters from a YAML config file, run a computation, and save results to both CSV and JSON formats.

String Formatting and File I/O Patterns

python
Demonstrates f-string formatting for scientific output, reading YAML/JSON configs, writing CSV results, and using the logging module.
# Code from: ch01/python/string_io_patterns.py
# Load from backend supplements endpoint

f-String Format Spec Explorer

Enter a number and try different format specifications to see how Python renders it. Useful for finding the right spec for your use case.

Parameters
3141.592653
3

Common Mistake: The Mutable Default Argument Trap

Mistake:

Using a mutable object (list, dict) as a default argument:

def add_result(result, results=[]):  # BUG!
    results.append(result)
    return results

add_result("a")  # ['a']
add_result("b")  # ['a', 'b'] — the list persists across calls!

Correction:

Use None as the default and create the mutable inside the function:

def add_result(result, results=None):
    if results is None:
        results = []
    results.append(result)
    return results

This is one of Python's most notorious gotchas. The default value is evaluated once at function definition time, not at each call.

Scientific Python I/O Format Landscape

Scientific Python I/O Format Landscape
Common file formats in scientific Python: when to use each. CSV for simple tabular data, JSON for nested metadata, YAML for configs, HDF5 for large numerical arrays, pickle for Python objects.

File Format Comparison

FormatBest ForHuman ReadablePython ModuleSpeed
CSVSimple tabular dataYescsv / pandasFast
JSONNested configs, metadataYesjsonFast
YAMLConfiguration filesYespyyamlModerate
HDF5Large numerical arraysNoh5pyVery fast
PickleArbitrary Python objectsNopickleFast
NumPy .npySingle NumPy arrayNonumpyVery fast
NumPy .npzMultiple NumPy arraysNonumpyVery fast

Quick Check

What does f"{1.23456e-5:.2e}" produce?

"1.23e-05"

"0.00001"

"1.2e-05"

"1.23456e-05"

Key Takeaway

f-strings with format specs are your primary tool for scientific output. Use .2e for BER values, .1f for SNR in dB, and aligned columns for result tables. Use YAML for configs, CSV for results, and the logging module instead of print() for anything that matters.