How to Use pathlib in Python
In Python, the pathlib module allows you to manipulate file and directory (folder) paths as objects.
You can perform various operations, such as extracting file names, obtaining path lists, and creating or deleting files, more easily than with the traditional os.path module.
This article explains the basic usage of the pathlib module.
All sample code in this article assumes that the pathlib module has been imported. No additional installation is required since it is included in the standard library.
import pathlib
It is also common to import only the Path class. In this case, pathlib.Path() is used as Path().
from pathlib import Path
The following file and directory structure is used as an example.
temp/
├── dir/
│ └── sub_dir/
│ └── file2.txt
└── file.txt
Path objects
The pathlib.Path() constructor
The pathlib module allows you to manipulate paths as objects.
You can create a Path object using the pathlib.Path() constructor by specifying a path string. It can be either a relative or an absolute path.
p_file = pathlib.Path('temp/file.txt')
print(p_file)
# temp/file.txt
print(type(p_file))
# <class 'pathlib.PosixPath'>
Omitting the argument yields a relative path representing the current working directory. Equivalent to pathlib.Path('.').
print(pathlib.Path())
# .
print(pathlib.Path() == pathlib.Path('.'))
# True
pathlib.Path() creates an instance of a class according to the execution environment. For example, it creates a PosixPath instance on Unix-like systems and a WindowsPath on Windows.
PosixPath and WindowsPath are subclasses of Path.
print(issubclass(pathlib.PosixPath, pathlib.Path))
# True
print(issubclass(pathlib.WindowsPath, pathlib.Path))
# True
In most cases, there is no need to distinguish between PosixPath and WindowsPath for use, and in this article, objects of both types are collectively referred to as Path objects.
Path and PurePath
Path is known as a concrete path, with PurePath as its parent class.
PurePath provides purely computational operations without filesystem access, while Path provides I/O operations, such as reading or writing files. Since Path is a subclass of PurePath, all methods and attributes of PurePath are also available in Path.
print(issubclass(pathlib.Path, pathlib.PurePath))
# True
For example, to handle Windows-style paths on a Unix machine (or vice versa), create PurePosixPath or PureWindowsPath instances. However, for actual file and directory processing, pathlib.Path() should suffice.
Methods and attributes of Path
Various operations can be performed using the methods and attributes of the Path object.
For example, to determine if the path points to a file, use the is_file() method, and to get the extension as a string, use the suffix attribute.
p_file = pathlib.Path('temp/file.txt')
print(p_file.is_file())
# True
print(p_file.suffix)
# .txt
Note that suffix is an attribute of PurePath, but since PurePath is inherited by Path, it can also be used from instances of Path.
Thus, the basic flow of using pathlib is to create a Path object that points to the desired file or directory and then manipulate it with its methods and attributes.
Handle non-existent paths
It is also possible to create Path objects for non-existent paths. The exists() method returns False for these paths.
p_new_file = pathlib.Path('temp/new_file.txt')
print(p_new_file.exists())
# False
New files or directories can be created from objects of non-existent paths. For example, the touch() method creates an empty file.
p_new_file.touch()
print(p_new_file.exists())
# True
You can also chain methods in a single line.
pathlib.Path('temp/new_file2.txt').touch()
Using the iterdir() method to list the contents of a directory allows you to verify the presence of newly created files.
for p in pathlib.Path('temp').iterdir():
print(p)
# temp/file.txt
# temp/new_file.txt
# temp/new_file2.txt
# temp/dir
Navigate paths: /, joinpath(), parent, etc.
You can create Path objects for different directories or files based on an existing Path object, similar to navigating a directory tree.
Join paths
Using the / operator with Path objects and path strings concatenates paths.
p_dir = pathlib.Path('temp/dir')
p_sub_dir_file = p_dir / 'sub_dir' / 'file2.txt'
print(p_sub_dir_file)
# temp/dir/sub_dir/file2.txt
print(p_sub_dir_file.is_file())
# True
Paths can also be joined using the joinpath() method, which serves the same purpose as os.path.join().
p_sub_dir_file = p_dir.joinpath('sub_dir', 'file2.txt')
print(p_sub_dir_file)
# temp/dir/sub_dir/file2.txt
print(p_sub_dir_file.is_file())
# True
Move to parent directories
Concatenate ..
Concatenating .. moves to the parent directory.
p_dir = pathlib.Path('temp/dir')
p_file_join = p_dir.joinpath('..', 'file.txt')
print(p_file_join)
# temp/dir/../file.txt
The samefile() method checks if two paths refer to the same file. Note that the == operator returns False in this case.
p_file = pathlib.Path('temp/file.txt')
print(p_file.samefile(p_file_join))
# True
print(p_file == p_file_join)
# False
To convert a relative path into an absolute path, use the resolve() method.
print(p_file_join.resolve())
# /Users/mbp/Documents/my-project/python-snippets/notebook/temp/file.txt
print(p_file.resolve())
# /Users/mbp/Documents/my-project/python-snippets/notebook/temp/file.txt
print(p_file_join.resolve() == p_file.resolve())
# True
To convert an absolute path into a relative path, use the relative_to() method. It returns a relative path to the specified base path.
Utilizing cwd() method, you can convert an absolute path to a path relative to the current directory as follows.
print(p_file_join.resolve().relative_to(pathlib.Path.cwd()))
# temp/file.txt
The parent attribute
To move to the parent directory, you can also use the parent attribute.
p_dir = pathlib.Path('temp/dir')
print(p_dir.parent)
# temp
print(p_dir.parent.joinpath('file.txt'))
# temp/file.txt
However, note that parent is purely a lexical operation. It does not interpret ...
p_file_join = p_dir.joinpath('..', 'file.txt')
print(p_file_join)
# temp/dir/../file.txt
print(p_file_join.parent)
# temp/dir/..
print(p_file_join.parent.parent)
# temp/dir
The with_name() method
The with_name() method creates a new Path object with a different name in the same directory. This is simpler than moving to the parent directory and concatenating a different file name.
p_file = pathlib.Path('temp/file.txt')
print(p_file.with_name('new_file.txt'))
# temp/new_file.txt
Convert Path objects to strings (str)
As shown in the examples so far, outputting a Path object with print() displays the path as a string, but its type is still Path (PosixPath or WindowsPath), not a string (str).
p_file = pathlib.Path('temp/file.txt')
print(p_file)
# temp/file.txt
print(type(p_file))
# <class 'pathlib.PosixPath'>
Use str() to convert a Path to a string.
s = str(p_file)
print(s)
# temp/file.txt
print(type(s))
# <class 'str'>
Specify Path objects as arguments to os module functions
Although os module functions traditionally require a path string, many functions now accept Path objects since Python 3.6.
For example, os.path.isfile() works correctly with both path strings and Path objects.
import os
print(os.path.isfile('temp/file.txt'))
# True
print(os.path.isfile(pathlib.Path('temp/file.txt')))
# True
Functions that now accept Path objects are noted in the official documentation.
Changed in version 3.6: Accepts a path-like object. os.path.isfile() — Python 3.12.2 documentation
Note that there is the is_file() method for Path objects corresponding to os.path.isfile(). For most functions of os, there are corresponding methods in Path objects, so there is rarely a need to use os functions directly.
Correspondence between os module and pathlib Module
The official documentation includes a list showing which methods of Path and PurePath objects correspond to functions in the os module.
Key correspondences include:
| Operation | os and os.path |
pathlib |
|---|---|---|
| Get current directory | os.getcwd() |
Path.cwd() |
Replace leading ~ with the home directory |
os.path.expanduser() |
Path.expanduser(), Path.home() |
| Check path existence | os.path.exists() |
Path.exists() |
| Check if a directory | os.path.isdir() |
Path.is_dir() |
| Check if a file | os.path.isfile() |
Path.is_file() |
| Check if a symbolic link | os.path.islink() |
Path.is_symlink() |
| Check if an absolute path | os.path.isabs() |
PurePath.is_absolute() |
| Convert to absolute path | os.path.realpath() |
Path.resolve() |
| Convert to relative path | os.path.relpath() |
PurePath.relative_to() |
| Get status | os.stat() |
Path.stat(), Path.owner(), Path.group() |
| Join paths | os.path.join() |
PurePath.joinpath() |
| Get base name | os.path.basename() |
PurePath.name |
| Get parent directory | os.path.dirname() |
PurePath.parent |
| Split and get extension | os.path.splitext() |
PurePath.stem, PurePath.suffix |
| Create directory | os.makedirs() |
Path.mkdir() |
| Remove directory | os.rmdir() |
Path.rmdir() |
| Remove file | os.remove(), os.unlink() |
Path.unlink() |