Python Pathlib
Python Pathlib
Trey Hunner
12 min. read • Python 3.9—3.13 • Nov. 18, 2024
Share
Tags
Files
I now use pathlib for nearly all file-related code in Python, especially when I need to
construct or deconstruct file paths or ask questions of file paths.
I'd like to make the case for Python's pathlib module... but first let's look at a cheat
sheet of common path operations.
You might think open accepts a string representing a filename. And you'd be right.
filename = "example.txt"
path = Path("example.txt")
path = Path("example.txt")
contents = path.read_text()
Python's pathlib.Path objects represent a file path. In my humble opinion, you
should use Path objects anywhere you work with file paths. Python's Path objects
make it easier to write cross-platform compatible code that works well with filenames in
various formats (both / and \ are handled appropriately).
Which operations are easier? That's what the rest of this article is all about.
Joining paths
One of the most common path-related operations is to join path fragments together.
For example, we might want to join a directory path to a filename to get a full file path.
We'll look at each, by using this Path object which represents our home directory:
>>> home.joinpath(".my_config.toml")
PosixPath('/home/trey/.my_config.toml')
The / operator
Passing multiple arguments to the Path class will also join those paths together:
>>> Path()
PosixPath('.')
>>> Path(".")
PosixPath('.')
However, I prefer Path.cwd(), which is a bit more explicit and it returns an absolute
path:
>>> Path.cwd()
PosixPath('/home/trey')
Absolute paths
Many questions you might ask of a path (like getting its directory) require absolute
paths. You can make your path absolute by calling the resolve() method:
>>> full_path
PosixPath('/home/trey/example.txt')
Need just the filename for your filepath? Use the name attribute:
>>> full_path.name
'example.txt'
Need to get the directory a file is in? Use the parent attribute:
>>> full_path.parent
PosixPath('/home/trey')
Need a file extension? Use the suffix attribute:
>>> full_path.suffix
'.txt'
Need the part of a filename that doesn't include the extension? There's a stem attribute:
>>> full_path.stem
'example'
But if you're using stem to change the extension, use the with_suffix method instead:
>>> full_path.with_suffix(".md")
PosixPath('/home/trey/example.md')
Listing files in a directory
Need to list the files in a directory? Use the iterdir method, which returns a
lazy iterator:
You could open the file and use the read method:
contents = path.read_text()
For writing the entire contents of a file, there's also a write_text method:
Need to make a new directory if it doesn't already exist? Use the mkdir method
with exist_ok set to True:
>>> templates.mkdir(exist_ok=True)
>>> templates.is_dir()
True
Need to automatically create parent directories of a newly created directory? Pass
the parents argument to mkdir:
BASE_DIR = Path(__file__).resolve().parent.parent
This will set BASE_DIR to the directory just above the settings module.
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
I find the pathlib version much more readable.
>>> print(documents1)
C:\Users\Trey\Documents
You might ask "why even care about / vs \ on Windows if / pretty much always
works"? Well, if you're mixing and matching \ and /, things can get weird... especially
if you're comparing two paths to see whether they're equal!
With the automatic normalization done by pathlib.Path objects, you'll never need to
worry about issues with mixing and matching / and \ on Windows.
Cross-platform compatible?
Why not just use the split and join string methods to split and join
with / or \ characters?
Here's a pathlib cheat sheet, showing the new pathlib way and the old os.path, os,
or glob equivalent for many common operations.
Note that a somewhat similar comparison table exists in the pathlib documentation.
That doesn't mean you can't do this with pathlib. It just means you'll need to write
your own function, just as you would have before pathlib:
def subdirectories_of(path):
return (
path
for subpath in path.iterdir()
if subpath.is_dir()
)
Working with pathlib is often easier than working with alternative Python tools.
Finding help on pathlib features is as simple as passing a pathlib.Path object to the
built-in help function.
Nearly every utility built-in to Python which accepts a file path will also accept
a pathlib.Path object.
For example the shutil library's copy and move functions
accept pathlib.Path objects:
import subprocess
import sys
subprocess.run([sys.executable, Path("my_script.py")])
You can use pathlib everywhere.
If you really need a string representing your file path, pathlib.Path objects can be
converted to strings either using the str function or an f-string:
>>> str(path)
'readme.txt'
>>> f"The full path is {path.resolve()}"
'The full path is /home/trey/proj/readme.txt'
But I can't remember the last time I needed to explicitly convert
a pathlib.Path object to a string.
Unless I'm simply passing a single string to the built-in open function, I pretty much
always use pathlib when working with file paths.
Mark as read
A Python tip every week
Need to fill-in gaps in your Python skills?
Sign up for my Python newsletter where I share one of my favorite Python tips every
week.
Table of Contents
Mark as read
Next Up 02:58
Unicode character encodings
When working with text files in Python, it's considered a best practice to specify the character encoding that