惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - Franky
云风的 BLOG
云风的 BLOG
人人都是产品经理
人人都是产品经理
博客园 - 叶小钗
Engineering at Meta
Engineering at Meta
Vercel News
Vercel News
Y
Y Combinator Blog
B
Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Check Point Blog
M
MIT News - Artificial intelligence
Jina AI
Jina AI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Apple Machine Learning Research
Apple Machine Learning Research
Hugging Face - Blog
Hugging Face - Blog
阮一峰的网络日志
阮一峰的网络日志
罗磊的独立博客
Stack Overflow Blog
Stack Overflow Blog
F
Fortinet All Blogs
博客园 - 司徒正美
I
InfoQ
Google DeepMind News
Google DeepMind News
GbyAI
GbyAI
U
Unit 42

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
"Stop Using os.path — Python pathlib Makes File Handling ...
Kai Thorne · 2026-06-14 · via DEV Community

Kai Thorne

If you're still writing os.path.join("dir", "subdir", "file.txt"), you're doing file paths the hard way.

Python 3.4 introduced pathlib — a modern object-oriented approach to filesystem paths. And since Python 3.6, it's been "the way" according to the standard library docs themselves. Yet I still see tutorials and production code alike clinging to the old string-based os.path functions.

Let me show you why pathlib is the upgrade you didn't know you needed.

The Core Idea: Paths Are Objects, Not Strings

The fundamental shift is simple: instead of passing strings around and hoping functions parse them correctly, you work with Path objects that have methods for everything.

from pathlib import Path

# Old way
import os.path
config_path = os.path.join(os.path.dirname(__file__), "config", "settings.yaml")

# pathlib way
config_path = Path(__file__).parent / "config" / "settings.yaml"

The / operator works with paths because Path overrides it. No more os.path.join nesting. No more forgetting a separator.

What I Actually Use pathlib For Every Day

1. Traversing Directories

Need to find all markdown files in a project tree?

for md_file in Path("docs").rglob("*.md"):
    print(md_file.relative_to(Path.cwd()))

.rglob("*pattern*") recursively matches. .glob("*pattern*") is non-recursive. Both return generators, so they're memory-friendly even on large trees.

Compare with os.walk + fnmatch:

# Old way
import os, fnmatch
for root, dirs, files in os.walk("docs"):
    for f in fnmatch.filter(files, "*.md"):
        print(os.path.relpath(os.path.join(root, f)))

The pathlib version is 3x fewer lines and doesn't make you think about joining paths inside a loop.

2. Reading and Writing Files

This is where pathlib shines brightest:

# Read
data = Path("config.json").read_text()

# Write  
Path("output.txt").write_text("Hello, pathlib!")

# Binary
bytes_data = Path("image.png").read_bytes()
Path("copy.png").write_bytes(bytes_data)

No with open(...) as f: for simple operations. No forgetting to close files. No encoding shenanigans with default system encoding — read_text() uses UTF-8 by default.

3. Checking File Properties

p = Path("some_file.py")

p.exists()          # Does it exist?
p.is_file()         # Is it a file?
p.is_dir()          # Is it a directory?
p.stat().st_size    # File size in bytes
p.stat().st_mtime   # Last modified timestamp
p.suffix            # '.py'
p.stem              # 'some_file' (name without suffix)
p.name              # 'some_file.py'
p.parent            # Path('.') — the containing directory

All on the same object. No os.path.getsize(), os.path.isdir(), os.path.splitext() from five different import lines.

4. Creating and Deleting

# Create directory (like mkdir -p)
Path("data/2024/raw").mkdir(parents=True, exist_ok=True)

# Create a temp file
Path("/tmp/scratch.txt").touch()

# Delete
Path("old_backup.zip").unlink(missing_ok=True)  # Python 3.8+

# Recursive delete
import shutil
shutil.rmtree(Path("temp_dir"))

The parents=True flag is the -p flag you always wanted. exist_ok=True means no crash if the directory already exists.

5. Working With Relative Paths

base = Path("/home/user/projects")
target = Path("/home/user/projects/src/utils/helpers.py")

# Relative path from base to target
rel = target.relative_to(base)  # Path('src/utils/helpers.py')

# Going back up
common = Path("/home/user/projects/src")
target.relative_to(common)       # Path('utils/helpers.py')

Great for generating file listings, build scripts, or log messages that don't leak absolute filesystem structure.

The Pattern That Converted Me

Here's the exact refactor that made me a pathlib believer:

Before:

import os
import json

def load_config(env):
    base = os.path.dirname(os.path.abspath(__file__))
    config_dir = os.path.join(base, 'config')
    config_file = os.path.join(config_dir, f'{env}.json')

    if not os.path.exists(config_file):
        raise FileNotFoundError(f"No config for {env}")

    with open(config_file, 'r') as f:
        return json.load(f)

After:

from pathlib import Path
import json

def load_config(env):
    config_file = Path(__file__).parent / 'config' / f'{env}.json'

    if not config_file.exists():
        raise FileNotFoundError(f"No config for {env}")

    return json.loads(config_file.read_text())

Shorter. Cleaner. No import soup. No manual file handle management.

When You Still Need os.path

There are a few things os.path does that pathlib doesn't directly replace:

  • Low-level path splitting (os.path.splitdrive())
  • Some edge cases with UNC paths on Windows
  • Compatibility with code that strictly takes strings

But for 95% of everyday file operations, pathlib is the better choice. And if you need os.path functions, you can always get the string back with str(path_object).

Quick Reference

Task os.path way pathlib way
Join paths os.path.join(a, b) Path(a) / b
Get extension os.path.splitext(f)[1] Path(f).suffix
Check if file os.path.isfile(p) Path(p).is_file()
Read file open(p).read() Path(p).read_text()
Walk recursively os.walk() Path().rglob('*')
Get parent dir os.path.dirname(p) Path(p).parent
File name os.path.basename(p) Path(p).name
Absolute path os.path.abspath(p) Path(p).resolve()

Bottom Line

pathlib isn't just syntactic sugar — it changes how you think about file paths. Instead of assembling strings and passing them to helper functions, you ask a Path object to do the work. The result is code that's shorter, more readable, and harder to get wrong.

If you're on Python 3.6+, there's no reason not to use it. Your future self (and your code reviewers) will thank you.


Working with files is just one part of writing clean Python. For more Python patterns, check out the 100+ AI Coding Prompts for Developers — tested across Python, JavaScript, and TypeScript for debugging, refactoring, and shipping faster.