pathlib & os
pathlib provides object-oriented paths (Path) for join, read, glob, and mkdir. os and os.path remain for low-level flags, environment variables, and process ids - combine both in production code.
Search across all documentation pages
pathlib provides object-oriented paths (Path) for join, read, glob, and mkdir. os and os.path remain for low-level flags, environment variables, and process ids - combine both in production code.
from pathlib import Path
root = Path(__file__).resolve().parent
config = root / "config" / "app.toml"
config.parent.mkdir(parents=True, exist_ok=True)
config.write_text("key = 'value'\n", encoding="utf-8")When to reach for this:
glob / rglobos.environ, os.getcwdimport os
from pathlib import Path
def find_py_files(src: Path, limit: int = 5) -> list[Path]:
return sorted(src.rglob("*.py"))[:limit]
def ensure_cache() -> Path:
cache = Path(os.environ.get("APP_CACHE", Path.home() / ".cache" / "demo"))
cache.mkdir(parents=True, exist_ok=True)
return cache
root = Path.cwd()
print("cwd", root)
print("sample files", find_py_files(root))
stamp = ensure_cache() / "last.run"
stamp.write_text("ok", encoding="utf-8")
print(stamp.read_text(encoding="utf-8"))What this demonstrates:
/ operator joins path segments portablyrglob recursive glob from rootmkdir(parents=True, exist_ok=True) creates tree| Task | pathlib | os |
|---|---|---|
| Join | base / "x" | os.path.join |
| Exists | p.exists() | os.path.exists |
| Env | - | os.environ |
| chmod | p.chmod | os.chmod |
read_text/write_text need encodingread_bytes for images, pickles, archivesresolve() or pass base dir.os.walk pruning, or dedicated index.| Alternative | Use When | Don't Use When |
|---|---|---|
| os.walk | Fine-grained prune | Simple glob enough |
| tempfile module | Secure temp files | Fixed cache dir |
| shutil | copy/move tree | Single file pathlib |
Accept os.PathLike (Path | str) in public functions; convert internal to Path.
resolve() follows symlinks and makes absolute - use before comparing paths.
Path.home() or ~ expand via expanduser().
shutil.rmtree - pathlib has no recursive delete until careful unlink/rmdir.
No stdlib great watcher - watchdog PyPI on some platforms; polling glob for simple cases.
Affects child processes - document side effects in CLI tools.
is_symlink, readlink, resolve behavior - know your deployment FS.
Path objects immutable; filesystem itself can race - same as os.
Python 3 paths are str (unicode) - still watch NFC normalization on macOS.
Configure as str path; use Path in new code inside Django for consistency.
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 19, 2026