PythonMastery

Build file paths with pathlib, not string joins

pathlib.Path joins with /, splits a name into stem and suffix, and swaps extensions in one call. Fewer string bugs, and it reads like the path it builds.

Paths look like strings, so people build them with strings: +, "/", split("."). That works until a folder name has a dot in it or the code runs on Windows. pathlib treats a path as a path, and every common question has a named answer.

Before

python
import os

folder = "reports/2026"
name = "sales.q3.csv"

full = folder + "/" + name
base = name.split(".")[0]
ext = name.split(".")[-1]
backup = full.replace(".csv", ".bak")

print(full)
print(base, ext)
print(backup)
print(os.path.dirname(full))
output
reports/2026/sales.q3.csv
sales csv
reports/2026/sales.q3.bak
reports/2026

base came out as sales, not sales.q3: splitting on the first dot threw part of the name away.

After

python
from pathlib import PurePosixPath as Path

full = Path("reports") / "2026" / "sales.q3.csv"

print(full)
print(full.stem, full.suffix)
print(full.with_suffix(".bak"))
print(full.parent)
print(full.name)
output
reports/2026/sales.q3.csv
sales.q3 .csv
reports/2026/sales.q3.bak
reports/2026
sales.q3.csv

In your own code, import Path itself; it picks the right flavour for the operating system. The examples use PurePosixPath so they print the same forward slashes everywhere.

Why it works

/ on a Path means "join", so there's no separator to get wrong. stem is everything before the last dot and suffix is the last dot onwards, which is what you almost always mean. And a real Path does the file work too: .exists(), .read_text(), .mkdir(parents=True) and .glob("*.csv") replace half of os and os.path.

python
from pathlib import PurePosixPath as Path

logs = [Path("logs/app.log"), Path("logs/app.log.1"), Path("logs/archive.tar.gz")]
for p in logs:
    print(p.name, "->", p.suffixes)
output
app.log -> ['.log']
app.log.1 -> ['.log', '.1']
archive.tar.gz -> ['.tar', '.gz']

When not to use it

Some older libraries still want a plain string; pass str(path) and move on. And for a path that arrives from outside, such as a user's upload name, pathlib tidies it but doesn't make it safe: check it stays inside the folder you expect before you open it.

Learn it properly: File I/O, Pathlib, and Large Files, Files: Reading and Writing to Disk