Modern File Paths with pathlib
For years Python developers juggled file paths as fragile strings with os.path . pathlib replaced all of that with clean Path objects that know how to join, search, read, and write. It's the modern standard, and once you use it you won't go back.
Learn Modern File Paths with pathlib in our free Python course — a beginner-friendly interactive lesson with runnable examples, a practice exercise and a…
Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
You'll build paths with the / operator, inspect filenames, find files with glob patterns, and read and write files in one line.
The old way joined strings by hand — brittle and platform-dependent. The new way uses the / operator, which reads exactly like a real path:
A Path object exposes every part of a filename as a simple attribute — no more string slicing:
Before reading or writing, you often need to know what's actually there. These return booleans:
These checks prevent the most common file errors. Checking exists() before reading turns a crash into a clean message.
For small text and data files, read_text and write_text handle opening and closing the file for you — no with open(...) boilerplate:
Need every CSV in a folder? Every Python file in an entire project tree? glob and rglob make it trivial:
A genuinely useful script: scan a messy "Downloads" folder and sort every file into a subfolder by its extension. This is the kind of thing people actually run weekly:
Every line uses pathlib: iterdir to list, suffix to classify, / to build the destination, mkdir to create folders, rename to move. No string juggling anywhere.
These lines should make a folder and write a file inside it, but they're scrambled. Find the order:
Import, build the Path, create the folder (with parents so data/ is made too), then write the file. You must create the folder before writing into it.
a/b/c.txt (on Windows: a\b\c.txt ) — the / operator joins path parts using the OS separator.
.gz — .suffix is only the LAST extension. To get both you'd use .suffixes , which returns ['.tar', '.gz'] .
today — .stem is the filename without its extension and without the folder. ( .name would be today.md .)
Files and folders bend to your will now!
You can build paths with the / operator, inspect every part of a filename, check existence, read and write in one line, find files with glob, and create folders safely. pathlib is the modern way and you've mastered the essentials.
🚀 Up next: Checkpoint — A Real-World Script — combine everything you've learned into one practical program.
Practice quiz
What does Path("a") / "b" / "c.txt" produce on Linux?
- a/b/c.txt
- a\b\c.txt
- abc.txt
- a.b.c.txt
Answer: a/b/c.txt. The / operator joins path parts with the OS separator — forward slashes on Linux/Mac.
What is Path("archive.tar.gz").suffix?
- .tar.gz
- .tar
- .gz
- tar.gz
Answer: .gz. .suffix returns only the LAST extension. Use .suffixes to get ['.tar', '.gz'].
What is Path("/data/notes/today.md").stem?
- today.md
- today
- notes
- .md
Answer: today. .stem is the filename without its final extension and without the folder.
What is Path("/home/user/reports/q3.final.csv").name?
- q3
- q3.final
- q3.final.csv
- reports
Answer: q3.final.csv. .name is the full final component, including all extensions.
Which attribute gives the containing folder of a path?
- .parent
- .stem
- .suffix
- .name
Answer: .parent. For 'data/report.csv', .parent is 'data' — the folder holding the file.
What does Path("/data/report.csv").with_suffix(".json") return?
- /data/report.json.csv
- /data/report.json
- /data/.json
- report.json
Answer: /data/report.json. with_suffix swaps the last extension, giving /data/report.json.
Which method searches recursively through ALL subfolders for a pattern?
- glob
- iterdir
- rglob
- walk
Answer: rglob. rglob('*.py') recurses into every subfolder; glob only looks in one folder.
Which call creates a folder chain safely without erroring if it already exists?
- p.mkdir()
- p.mkdir(parents=True, exist_ok=True)
- p.makedirs()
- p.create(recursive=True)
Answer: p.mkdir(parents=True, exist_ok=True). parents=True makes missing parents (like mkdir -p); exist_ok=True avoids FileExistsError.
Which one-line call returns a file's whole contents as a string?
- p.read()
- p.read_text()
- p.text()
- p.open_text()
Answer: p.read_text(). read_text() opens, reads, and closes the file, returning a str — no with-open needed.
What does p.write_text("hi") do if the file already exists?
- Appends to the end
- Raises FileExistsError
- Overwrites the entire file
- Does nothing
Answer: Overwrites the entire file. write_text overwrites the whole file every time. Use p.open('a') to append instead.