Strings & f-strings
Python str objects represent Unicode text. f-strings embed expressions directly in literals, making formatting readable and fast. Knowing when to use bytes prevents encoding bugs at system boundaries.
Search across all documentation pages
Python str objects represent Unicode text. f-strings embed expressions directly in literals, making formatting readable and fast. Knowing when to use bytes prevents encoding bugs at system boundaries.
name = "Ada"
score = 97.456
line = f"{name:>10} | {score:.1f}%"
multiline = f"""Report for {name}
Score: {score:.2f}"""
raw_path = r"C:\new\data\file.txt"When to reach for this:
from pathlib import Path
def build_report(rows: list[dict[str, object]]) -> str:
header = f"{'name':<12} {'role':<10} {'score':>6}"
lines = [header, "-" * len(header)]
for row in rows:
lines.append(
f"{row['name']:<12} {row['role']:<10} {row['score']:>6.1f}"
)
return "\n".join(lines)
def slugify(text: str) -> str:
cleaned = text.strip().lower()
for ch in " /_":
cleaned = cleaned.replace(ch, "-")
while "--" in cleaned:
cleaned = cleaned.replace("--", "-")
return cleaned.strip("-")
def read_utf8_file(path: Path) -> str:
return path.read_text(encoding="utf-8")
def to_bytes_payload(message: str) -> bytes:
return message.encode("utf-8")
if __name__ == "__main__":
sample = [
{"name": "Ada", "role": "admin", "score": 98.2},
{"name": "Linus", "role": "dev", "score": 91.0},
]
print(build_report(sample))
print(slugify(" Hello World / API "))
print(to_bytes_payload("ok"))What this demonstrates:
:<12, :>6.1f)strip, lower, and replace form a simple slug pipelinePath.read_text(encoding="utf-8") avoids platform-default encoding surprisesstr.encode produces bytes for wire protocolsstr is Unicode; indexing returns one-code-point strings (mostly).f"{x=}" shows name and value (3.8+).bytes holds 0-255 values; decode with an explicit codec.unicodedata.normalize helps compare visually similar characters.| Method | Purpose |
|---|---|
split(sep) | Break on delimiter |
join(iterable) | Concatenate with separator |
strip(chars) | Trim ends |
replace(old, new) | Substitute substrings |
removeprefix/prefix | Trim known prefix (3.9+) |
text = " hello "
text.strip().casefold() == "HELLO".casefold() # case-insensitive compare
b"\xc3\xa9".decode("utf-8") # bytes -> str
"résumé".encode("ascii", errors="replace") # lossy fallbackopen("f.txt") uses locale default on some systems. Fix: Always pass encoding="utf-8".b"hi" + "there" raises TypeError. Fix: Encode or decode explicitly first.+= in loops is slow for massive text. Fix: Collect in a list and "".join(lines)."café" != "café" with different combining characters. Fix: Normalize before compare.| Alternative | Use When | Don't Use When |
|---|---|---|
| f-strings | Most formatting | Need lazy template for i18n catalogs |
str.format | Positional templates from config | Simple inline formatting |
Template | Safer substitution from user input | Full format spec needs |
regex (re) | Complex pattern extraction | Simple split suffices |
Generally yes - expressions are evaluated once at runtime with less overhead. Prefer f-strings for new code.
Network protocols, binary file formats, and crypto digests operate on bytes. Convert at the boundary.
UTF-8 for text files, HTTP JSON, and logs unless a spec mandates otherwise.
Use triple quotes: f"""line1\n{name}""". Newlines in the literal are preserved.
r"\\server\share" treats backslashes literally - handy for regex and Windows paths in docs.
f"{1_000_000:,}" produces 1,000,000. Underscores in literals are cosmetic for readability too.
Yes: f"{len(items)} items". Keep expressions simple for readability.
str.strip removes only ends. For all occurrences use replace or re.sub.
Aggressive case normalization for comparisons - better than lower() for Unicode matching.
Never interpolate user input. Use parameterized queries from your DB driver or ORM.
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 16, 2026