Python pathlib: Stop Building File Paths by Hand
Build, check and search file paths with pathlib instead of string concatenation. After this, the same script works on Windows, macOS and Linux.
Course content
Sign in to save your progress.
-
Set Up Projects That Don't Break Each Other
-
Python Virtual Environments and pip: One Project, One Environment
-
Pinning Python Dependencies With requirements.txt
-
-
-
Organize Code Other People Can Read
-
Python Modules and Packages: Splitting One Big File
-
Python Imports: Why ModuleNotFoundError Keeps Happening
-
Python Classes: When a Dictionary Is No Longer Enough
-
-
-
Work With Real Files
-
Python File Handling: Open, Read, Write, and Always Use with
-
Python pathlib: Stop Building File Paths by Hand
-
Reading, Cleaning and Writing CSV Data in Python
-
-
-
Shorter Code That Still Says What It Does
-
Python Comprehensions: Lists, Sets and Dictionaries
-
When a Comprehension Should Be a Plain Loop
-
-
-
Prove It Works Before Someone Else Finds Out
-
Python Testing Basics With pytest
-
Debugging Python With print, logging and pdb
-
-
- Final Check: Python Intermediate
Stop gluing file paths together with + and "/". Use pathlib. It is in the standard library, it handles Windows and macOS/Linux differences for you, and the code reads like what it does.
Skip ahead: If you already use Path, the / operator, glob and Path(__file__).parent, continue to "Reading, Cleaning and Writing CSV Data in Python."
Why this matters
String paths break in quiet ways. folder + "data.csv" forgets the slash and gives reportsdata.csv. A hard-coded "C:\\Users\\..." only works on one computer. A backslash in a normal string turns "\t" into a tab. None of these crash where the mistake is. They crash later, at the open() call, with a path that looks almost right.
Building paths
from pathlib import Path
base = Path("reports")
monthly = base / "2026" / "october" / "sales.csv"
print(monthly)
print(monthly.name)
print(monthly.stem)
print(monthly.suffix)
print(monthly.parent)
reports/2026/october/sales.csv
sales.csv
sales
.csv
reports/2026/october
The / operator joins parts with the right separator for the system. On Windows, the same code prints reports\2026\october\sales.csv. You don't write either separator yourself.
Changing part of a path
from pathlib import Path
source = Path("exports/orders_2026-10.csv")
print(source.with_suffix(".json"))
print(source.with_name("orders_clean.csv"))
print(source.with_stem(source.stem + "_backup"))
exports/orders_2026-10.json
exports/orders_clean.csv
exports/orders_2026-10_backup.csv
No slicing strings, no counting characters, no bugs when a file name has two dots. (with_stem needs Python 3.9 or newer.)
Checking and creating
from pathlib import Path
out_dir = Path("output") / "2026"
print(out_dir.exists())
out_dir.mkdir(parents=True, exist_ok=True)
print(out_dir.exists(), out_dir.is_dir())
summary = out_dir / "summary.txt"
summary.write_text("3 orders processed\n", encoding="utf-8")
print(summary.read_text(encoding="utf-8"), end="")
False
True True
3 orders processed
parents=True creates the missing folders in between. exist_ok=True means no error when the folder is already there, so the script can run twice. read_text and write_text open and close the file for you. They are fine for small files. For big files or line-by-line work, use path.open() in a with block, exactly like the previous lesson.
Finding files
from pathlib import Path
inbox = Path("inbox")
(inbox / "2026").mkdir(parents=True, exist_ok=True)
for name in ["a.csv", "b.csv", "notes.txt", "2026/c.csv"]:
(inbox / name).write_text("x\n", encoding="utf-8")
print(sorted(p.name for p in inbox.glob("*.csv")))
print(sorted(str(p) for p in inbox.rglob("*.csv")))
['a.csv', 'b.csv']
['inbox/2026/c.csv', 'inbox/a.csv', 'inbox/b.csv']
glob searches one folder. rglob also searches every subfolder. The order of results isn't guaranteed, so sort them if the order matters, for example when processing files by date in the name.
The fix for "file not found, but it's right there"
A relative path like Path("data.csv") is relative to the folder you ran Python from, not the folder the script is in. Run the script from somewhere else, or from a scheduled task, and it looks in the wrong place. To find files that live next to the script, start from the script's own location:
id,total
1,1200
# tool/report.py
from pathlib import Path
HERE = Path(__file__).resolve().parent
data_file = HERE / "data.csv"
print(data_file.name, data_file.exists())
print(Path("data.csv").exists())
data.csv True
False
Run from the folder above tool, the plain relative path fails while the HERE version still finds the file. resolve() turns the path into a full absolute path, so it doesn't matter where you started.
⚠ Warning: Be careful with code that deletes files found by glob or rglob, like a cleanup that calls unlink() on every match. Print the list first and check it. A wrong base folder, or an rglob where you meant glob, deletes far more than you intended, and deleted files don't go to the Recycle Bin.
Windows paths in strings
If you must write a Windows path in your code, use a raw string or forward slashes. Both work on Windows:
print(len("C:\temp\new")) # \t and \n became a tab and a newline
print(len(r"C:\temp\new")) # raw string: backslashes kept
print("C:/temp/new") # forward slashes also work on Windows
9
11
C:/temp/new
Better still, don't hard-code full paths at all. Build them from Path.home(), from HERE, or from a setting.
Common mistakes
- Converting back to strings too early. Most functions, including
open(), acceptPathobjects. Keep it aPathuntil something truly needs a string, then usestr(path). - Forgetting
exist_ok=True. The script works the first time and fails withFileExistsErrorthe second time. - Mixing
os.pathandpathlibin the same function. It works, but it is harder to read. Pick one per project. For new code, pickpathlib.
💡 Tip: When a path is wrong and you can't see why, print path.resolve(). It shows the full path Python is actually using, which usually makes the problem obvious.
What happens if you skip this step
Your paths work on the computer you wrote them on, from the folder you usually run them from. The first time someone runs the script on another operating system, from another folder, or from a scheduler, it fails with "file not found" while the file is clearly sitting right there.
If you moved your project folder to another drive today, how many paths in your code would you need to change?
About
Build, check and search file paths with pathlib instead of string concatenation. After this, the same script works on Windows, macOS and Linux.
- Duration
- 5 min
- Last update
- 09/21/2026
Comments (0)
Sign in to commentNo comments yet.