File Paths (pathlib)
Before pathlib, working with file paths in Python meant manipulating plain strings with the os.path module — joining them with os.path.join(), splitting them with os.path.splitext(), and so on. It worked, but it was easy to get wrong, especially across operating systems with different path separators. The pathlib module, introduced in Python 3.4, represents a filesystem path as an object with methods and properties, which makes path code shorter, more readable, and automatically portable between Windows and Unix-like systems.
Why `pathlib.Path` Over `os.path`
Object-oriented: a path is a
Pathobject with methods, not a bare string you pass to free functions.Cross-platform:
Pathautomatically uses the correct separator (\on Windows,/elsewhere) for you.Chainable: methods and the
/operator can be strung together to build up complex paths readably.Readable:
Path("data") / "raw" / "file.csv"reads far more clearly than nestedos.path.join()calls.
from pathlib import Path
import os
# pathlib
config_path = Path("app") / "config" / "settings.json"
# equivalent with os.path
config_path_old = os.path.join("app", "config", "settings.json")
print(config_path)
print(config_path_old)
print(type(config_path))app\config\settings.json app\config\settings.json <class 'pathlib.WindowsPath'>
Creating Paths
A Path can be built from a string, and there are convenient class methods for common starting points like the current working directory or the user's home folder.
from pathlib import Path
relative = Path("some/dir")
current_dir = Path.cwd()
home_dir = Path.home()
print(relative)
print(current_dir)
print(home_dir)some\dir C:\Users\ada\projects\myapp C:\Users\ada
Joining Paths with `/`
pathlib overloads the division operator so that / joins path segments, reading almost exactly like the path itself. This replaces os.path.join() and avoids manually worrying about separators or duplicate slashes.
from pathlib import Path
import os
base = Path("projects") / "myapp"
log_file = base / "logs" / "2026-07-06.log"
print(log_file)
# The equivalent in os.path requires nested calls
log_file_old = os.path.join("projects", "myapp", "logs", "2026-07-06.log")
print(log_file_old)projects\myapp\logs\2026-07-06.log projects\myapp\logs\2026-07-06.log
Common `Path` Methods and Properties
Method / property | Description |
|---|---|
| Returns |
| Returns |
| Returns |
| The final path component, e.g. |
| The filename without its final suffix, e.g. |
| The file extension, e.g. |
| The containing directory as a |
| Creates the directory. Use |
| Yields |
| Returns the absolute, fully resolved path (symlinks and |
from pathlib import Path
p = Path("data/report.csv")
print(p.name)
print(p.stem)
print(p.suffix)
print(p.parent)
print(p.exists())
print(p.resolve())report.csv report .csv data False C:\Users\ada\projects\myapp\data\report.csv
Creating Directories
.mkdir() creates a single directory, and raises FileExistsError if it's already there. Passing parents=True creates any missing parent directories along the way, and exist_ok=True makes the call a no-op instead of raising when the directory already exists — the combination is the safest default for "make sure this directory exists" code.
from pathlib import Path
output_dir = Path("build") / "reports" / "2026"
output_dir.mkdir(parents=True, exist_ok=True)
print(output_dir.exists())True
Reading and Writing Without `open()`
For simple cases, Path objects can read and write file contents directly, without ever calling open() yourself. .read_text() and .write_text() handle opening, reading or writing, and closing the file in one call — and both accept an encoding argument just like open() does.
from pathlib import Path
note = Path("note.txt")
note.write_text("Remember to review the pull request.\n", encoding="utf-8")
print(note.read_text(encoding="utf-8"))Remember to review the pull request.
Worked Example: Listing Files with `.glob()`
.glob() searches a directory using shell-style wildcard patterns and yields matching Path objects lazily. It's a quick way to find every file of a certain type inside a folder, without manually filtering a directory listing.
from pathlib import Path
project_dir = Path("src")
for py_file in sorted(project_dir.glob("*.py")):
size = py_file.stat().st_size
print(f"{py_file.name} — {size} bytes")app.py — 1204 bytes config.py — 512 bytes utils.py — 2048 bytes
pathlib.Pathtreats a filesystem path as an object with methods, replacing mostos.pathstring manipulation.The
/operator joins path segments in a readable, cross-platform way..exists(),.is_file(),.is_dir(),.name,.stem,.suffix, and.parentcover the most common path questions..read_text()/.write_text()skipopen()entirely for simple whole-file reads and writes..glob()and.rglob()find files matching a pattern without manual directory-walking code.