pathlib β Object-Oriented File Paths#
What it is#
pathlib is part of the Python standard library (no install needed). It represents filesystem paths as Path objects instead of plain strings, giving you methods for reading, writing, navigating, and querying files β all in a cross-platform way that handles Windows backslashes automatically.
It replaces os.path, os.getcwd(), open() boilerplate, and glob.glob() for most filesystem tasks.
Quick example#
from pathlib import Path
p = Path("documents/readme.txt")
print(p.name) # filename with extension
print(p.stem) # filename without extension
print(p.suffix) # extension with dot
print(p.parent) # containing directory
print(p.parts) # tuple of path components
Output:
readme.txt
readme
.txt
documents
('documents', 'readme.txt')
When / why to use it#
- Any time you manipulate file paths β pathlib is cleaner and more readable than
os.path.join(). - Reading and writing files without managing file handles.
- Recursive directory searches with
rglob("*.py"). - Cross-platform code:
Pathuses the right separator on every OS.
[!TIP] Prefer
Pathoverstrfor all path values in new code. If a library requires a string, wrap:str(p)or usep.as_posix()for forward-slash strings.
Common pitfalls#
[!WARNING]
/operator builds paths, not divides βPath("/home") / "user" / "file.txt"is path concatenation. If you pass an absolute path as the right operand it replaces everything to the left:Path("/home") / "/etc/passwd"βPath("/etc/passwd").
[!WARNING]
Path.open()vsopen()β both work, butpath.read_text()/path.write_text()are shorter for simple file reads/writes and handle encoding arguments directly.
Special paths#
from pathlib import Path
print(Path.cwd()) # current working directory
print(Path.home()) # home directory (~)
print(Path("/").root) # "/"
Output:
/home/user/myproject
/home/user
/
Reading and writing#
from pathlib import Path
p = Path("notes.txt")
# Write text (creates or overwrites)
p.write_text("Hello\nWorld\n", encoding="utf-8")
# Read text
content = p.read_text(encoding="utf-8")
print(repr(content))
# Append (open explicitly)
with p.open("a") as f:
f.write("More text\n")
# Binary
p.write_bytes(b"\x89PNG\r\n")
data = p.read_bytes()
print(len(data), "bytes")
Output:
'Hello\nWorld\n'
6 bytes
Richer example β directory operations and glob#
from pathlib import Path
base = Path("/tmp/demo_project")
# Create a directory tree
(base / "src").mkdir(parents=True, exist_ok=True)
(base / "tests").mkdir(parents=True, exist_ok=True)
# Write some files
(base / "src" / "app.py").write_text("print('app')\n")
(base / "src" / "utils.py").write_text("# utilities\n")
(base / "tests" / "test_app.py").write_text("# tests\n")
(base / "README.md").write_text("# Demo\n")
# Find all Python files recursively
py_files = sorted(base.rglob("*.py"))
print("Python files:")
for f in py_files:
print(f" {f.relative_to(base)} ({f.stat().st_size} bytes)")
# Find only in src/ (non-recursive)
src_files = sorted((base / "src").glob("*.py"))
print("\nSrc files:")
for f in src_files:
print(f" {f.name}")
Output:
Python files:
src/app.py (13 bytes)
src/utils.py (14 bytes)
tests/test_app.py (9 bytes)
Src files:
app.py
utils.py
Checking existence and type#
from pathlib import Path
p = Path("/tmp/demo_project/src/app.py")
print(p.exists()) # True if path exists (any type)
print(p.is_file()) # True if regular file
print(p.is_dir()) # True if directory
print(p.is_symlink()) # True if symlink
Output:
True
True
False
False
Quick reference#
| Task | Code |
|---|---|
| Build path | Path("dir") / "sub" / "file.txt" |
| Absolute path | p.resolve() |
| Home dir | Path.home() |
| Current dir | Path.cwd() |
| Read text | p.read_text(encoding="utf-8") |
| Write text | p.write_text("content") |
| Read bytes | p.read_bytes() |
| Create dir | p.mkdir(parents=True, exist_ok=True) |
| List dir | list(p.iterdir()) |
| Glob (non-recursive) | list(p.glob("*.py")) |
| Glob (recursive) | list(p.rglob("*.py")) |
| File size | p.stat().st_size |
| Rename / move | p.rename(new_path) |
| Copy (no method β use) | shutil.copy2(src, dst) |
| Delete file | p.unlink() |
| Delete empty dir | p.rmdir() |
| Delete tree | shutil.rmtree(p) |
| Change extension | p.with_suffix(".txt") |
| Change name | p.with_name("other.txt") |
| Change stem | p.with_stem("other") |
| Relative path | p.relative_to(base) |
| Parent dirs | p.parents[0], p.parents[1], β¦ |