Skip to content
beginner Phase 14 · Python File & Data Processing

Pathlib & File System

Navigate and manipulate file paths with pathlib and os.path.

45m
0 problems
Topic Progress 0%

Path Objects and Composition

Path Objects and Composition

pathlib.Path models paths as objects that join with / and decompose cleanly:

from pathlib import Path

p = Path("data") / "raw" / "sales.csv"
p.parts        # ('data', 'raw', 'sales.csv')
p.name         # 'sales.csv'
p.stem         # 'sales'
p.suffix       # '.csv'
p.parent       # data/raw
list(p.parents)          # ancestors, nearest first

Cross-platform joining is automatic: the same code yields data/raw/sales.csv on POSIX and backslashes on Windows. Conversions are explicit — str(path) for APIs, os.fspath(path) where a protocol is expected. Note p.absolute() prepends the cwd without touching the filesystem, while p.resolve() also normalizes .. and follows symlinks (non-strict by default since 3.6).

Reading, Writing, and Walking

Reading, Writing, and Walking

from pathlib import Path

cfg = Path("config.json")
cfg.write_text('{"mode": "prod"}', encoding="utf-8")   # always pass encoding
data = cfg.read_text(encoding="utf-8")

Path("out/logs").mkdir(parents=True, exist_ok=True)    # idempotent mkdir -p

for csv in Path("data").glob("**/*.csv"):              # rglob("**/*.csv") is identical
    print(csv, csv.stat().st_size)

if cfg.exists() and cfg.is_file():
    cfg.replace("config.bak")     # atomic overwrite/rename via os.replace

Directory walking replaces os.walk for most cases: sorted(d.iterdir()), filtering with is_dir()/suffix checks. Path.open() returns a normal file object, so context managers (with p.open() as f:) still manage closure. Never rely on default encodings — locale differences corrupt UTF-8 data on Windows.

Pitfalls and Interview Angles

Pitfalls and Interview Angles

Relative paths are promises, not facts. Path("in.csv") re-resolves against the current working directory every time it is used — a script run from another directory breaks. Anchor with Path(__file__).resolve().parent for file-relative resources.

pathlib rejects bytes paths. Byte-oriented code needs os functions; Path(os.fsdecode(raw)) bridges when necessary.

Glob surprises: patterns match names, not content; glob does not follow .. out of the tree in newer Pythons, and hidden files require glob(".*") explicitly.

Interview angle: contrast os.path.join (string-based, null-usable) with pathlib (object-oriented, richer API), and explain why resolve() is the safe way to canonicalize before comparing two paths.

Quiz

1. What does Path("a/b.txt").with_suffix(".md") return?

Question 1 options

2. Why anchor file lookups with Path(__file__).resolve().parent?

Question 2 options

3. Difference between absolute() and resolve()?

Question 3 options

Flashcards

Question

Path composition

Answer

Path("a") / "b" joins; .name/.stem/.suffix/.parent decompose; separators are platform-native.

Question

mkdir(parents=True, exist_ok=True)

Answer

Idempotent recursive creation — safe to run repeatedly.

Question

Glob vs rglob

Answer

glob("*.py") is one level; glob("**/*.py")/rglob("*.py") recurses the whole subtree.

Question

Encoding rule

Answer

Always pass encoding="utf-8" to read_text/write_text; defaults follow the locale.

Revision Notes

Key Takeaways

  • 1. Model paths as Path objects: / composition, structured decomposition, portable separators
  • 2. File IO with explicit encoding; directories with parents+exist_ok; discovery with glob/rglob
  • 3. Relative paths track the cwd — anchor to __file__ when location matters

Interview Tips

  • • Show the pathlib replacement for a messy os.path snippet and note the bytes-path caveat
  • • Explain resolve() versus absolute() when asked how you compare or canonicalize paths

Cheat Sheet

Path("a")/"b"; name/stem/suffix/parent; read_text/write_text(encoding="utf-8"); mkdir(parents=True, exist_ok=True); glob("**/*.py"); resolve() vs absolute().

Continue Learning

Before You Start

  • No prerequisites listed.

Next Topics