Stop Using os.path: Switch to Python's pathlib
Learn why Python's pathlib module is a cleaner, safer alternative to os.path for file path handling, with practical examples for everyday tasks like reading, writing, and searching files.
Here’s the article you requested, written in the specified style and format.
Stop Messing with os.path, Python’s pathlib is a Game Changer
For years, the standard way to handle file paths in Python was with os.path. And for years, it worked. But let’s be honest: it was clunky. You had to remember which function was os.path.join and which was os.path.sep. And every time you had a path as a string, you were one bad character away from a cross-platform crash.
That’s where pathlib comes in. It’s part of Python’s standard library since version 3.4, but a lot of folks still haven't made the switch. If you’re still writing os.path.join("data", "logs", "app.log"), it’s time to step up. pathlib treats paths like objects, not like brittle strings. And once you get used to it, you won’t want to go back.
Why Bother with pathlib?
First, let’s talk about the pain points of os.path. On Windows, file paths use backslashes. On Linux and macOS, they use forward slashes. If you hardcode a path, your script breaks on the wrong OS. os.path.join was supposed to fix that, but it still makes you juggle multiple function calls just to read a file.
pathlib cleans this up. Instead of passing strings around, you create a Path object. This object has methods like .read_text(), .write_text(), .glob(), and .exists(). It’s intuitive. You don’t have to remember if you need os.path.isfile() or os.path.exists()—the method is right there on the object.
Getting Started: The Path Object
The core of pathlib is the Path class. You start by pointing it at a location.
from pathlib import Path
# Relative path
log_folder = Path("data/logs")
# Absolute path
config_file = Path("/home/user/project/config.yaml")
That’s it. You now have a Path object. You can check if it exists, what type it is, and even read or write data directly.
The Common Tasks You Do Every Day
Let’s walk through a few real-world examples. Imagine you’re building a script for PythonSkillset to process logs. Here’s how pathlib handles it.
Check if a file exists:
if log_folder.exists():
print("We have a logs directory.")
Create a directory if it doesn’t exist:
log_folder.mkdir(parents=True, exist_ok=True)
parents=True creates parent directories automatically. exist_ok=True prevents an error if the directory already exists. This is a one-liner that used to require three lines with os.path and os.makedirs.
Read a file directly:
log_file = log_folder / "app.log"
content = log_file.read_text() # Returns a string
Yes, you can use the / operator to join paths. No more os.path.join. It reads naturally.
Write to a file:
log_file.write_text("This is a new log entry.\n")
Or for binary data:
log_file.write_bytes(b"binary data here")
No more with open(...) as f:. Just a single method call. Clean.
Finding Files: The glob() Method
One of the biggest time-savers is glob(). It searches for files matching a pattern, just like the shell.
for python_file in Path("src").glob("*.py"):
print(python_file)
This finds every .py file directly inside the src folder. If you want to search recursively, use rglob():
for all_py_files in Path("src").rglob("*.py"):
print(all_py_files)
This will find files in subdirectories too.
Real-World Example: Processing a Batch of Files
Let’s say you run a data analysis pipeline for PythonSkillset. You have a folder full of CSV files, and you need to validate each one. Here’s the pathlib approach:
from pathlib import Path
data_dir = Path("raw_data")
output_dir = Path("processed_data")
output_dir.mkdir(exist_ok=True)
for csv_file in data_dir.glob("*.csv"):
content = csv_file.read_text()
# Do your processing...
print(f"Processed: {csv_file.name}")
# Save to output folder with same name
(output_dir / csv_file.name).write_text(content)
Notice how csv_file.name gives you just the filename without the path. And you can join the output directory with the filename using /. It’s the little things that add up.
When to Stick with Strings
pathlib is amazing, but it’s not a silver bullet. Sometimes you still need a plain string—like when passing a path to a library that expects one (e.g., subprocess.run). In that case, just convert it:
path_str = str(my_path)
Or use .as_posix() to get a forward-slash version:
posix_str = my_path.as_posix()
The Bottom Line
If you’re still using os.path for anything beyond the simplest script, give pathlib a shot for your next project. It makes your code shorter, easier to read, and less prone to cross-platform bugs. And because it’s part of the standard library, you don’t need to install anything.
At PythonSkillset, we see too many codebases stuck in the past. Don’t let yours be one of them. Start treating your file paths like the objects they deserve to be.
Comments
Questions, corrections, and tips stay visible for everyone reading this page.
Join the discussion
No comments yet
Be the first to leave a note — it helps the next reader.