Python, pathlibの使い方(パスをオブジェクトとして操作・処理)
Pythonのpathlibモジュールを使うと、ファイル・ディレクトリ(フォルダ)のパスをオブジェクトとして操作・処理できる。
ファイル名・親ディレクトリの抽出やパス一覧の取得、ファイルの作成・削除など、一通りの処理が可能。慣れるとパス文字列を利用する従来のos.path
よりも使いやすい。
ここではpathlibモジュールの基本的な使い方を説明する。
本記事のサンプルコードでは以下のようにpathlibモジュールをインポートしている。標準ライブラリに含まれているので追加のインストールは不要。
import pathlib
以下のようにPath
クラスのみをインポートする例も多い。この場合、pathlib.Path()
はPath()
とする。
from pathlib import Path
以下のようなファイル・ディレクトリ構成を例とする。
temp/
├── dir/
│ └── sub_dir/
│ └── file2.txt
└── file.txt
pathlibを使った具体的な処理については以下の記事などを参照。
Pathオブジェクトを生成・処理
コンストラクタpathlib.Path()
pathlibモジュールではパスをオブジェクトとして操作する。
コンストラクタpathlib.Path()
でPath
オブジェクトを生成できる。引数にパスの文字列を指定する。相対パスでも絶対パスでもよい。
p_file = pathlib.Path('temp/file.txt')
print(p_file)
# temp/file.txt
print(type(p_file))
# <class 'pathlib.PosixPath'>
引数を省略すると、現在の作業ディレクトリ(カレントディレクトリ)を表す相対パス.
となる。pathlib.Path('.')
と等価。
print(pathlib.Path())
# .
print(pathlib.Path() == pathlib.Path('.'))
# True
pathlib.Path()
は実行環境に応じたクラスのインスタンスを生成する。上の例はMacで実行しているので、Unix系OSのクラスであるPosixPath
のインスタンスが生成される。Windowsで実行するとWindowsPath
となる。
PosixPath
とWindowsPath
はPath
のサブクラス。
print(issubclass(pathlib.PosixPath, pathlib.Path))
# True
print(issubclass(pathlib.WindowsPath, pathlib.Path))
# True
多くの場合、PosixPath
とWindowsPath
を意識して使い分ける必要はなく、本記事においてもPosixPath
とWindowsPath
のオブジェクトをまとめてPath
オブジェクトと呼ぶ。
具象パス(Path)と純粋パス(PurePath)
Path
は具象パスと呼ばれ、その親クラスとして純粋パスPurePath
がある。
PurePath
はファイルシステムへのアクセス(I/O)を伴わない処理を提供し、Path
はI/O処理も提供する。Path
はPurePath
のサブクラスなので、PurePath
のメソッドや属性もPath
から全て使用できる。
print(issubclass(pathlib.Path, pathlib.PurePath))
# True
Unixマシン上でWindows形式のパスを扱いたい(またはその逆)といった特別な場合は、純粋パスのクラスであるPurePosixPath
やPureWindowsPath
のインスタンスを生成する必要があるが、実際のファイルやディレクトリを処理する場合はpathlib.Path()
を使えばよい。
Pathのメソッドと属性
Path
オブジェクトのメソッドや属性によって様々な処理が可能となる。
例えば、パスが示すのがファイルか判定するにはis_file()
メソッド、拡張子を文字列で取得するにはsuffix
属性を使う。
p_file = pathlib.Path('temp/file.txt')
print(p_file.is_file())
# True
print(p_file.suffix)
# .txt
なお、suffix
はPurePath
の属性であるが、上述のようにPurePath
を継承するPath
のインスタンスからも使用可能。
このように、所望のファイルやディレクトリを示すパスのPath
オブジェクトを生成しメソッドや属性によって操作する、というのがpathlibを使った処理の基本的な流れとなる。
存在しないパスに対する処理
存在しないパスのオブジェクトを生成することもできる。パスの存在を確認するexists()
メソッドがFalse
を返す。
p_new_file = pathlib.Path('temp/new_file.txt')
print(p_new_file.exists())
# False
存在しないパスのオブジェクトから新しいファイルやディレクトリを作成できる。例えば、touch()
メソッドは空のファイルを作成する。
p_new_file.touch()
print(p_new_file.exists())
# True
メソッドをつなげて一行で書いてもよい。
pathlib.Path('temp/new_file2.txt').touch()
ディレクトリ直下のパス一覧のイテレータを取得するiterdir()
メソッドを使うと、ファイルが新規作成されていることが確認できる。
for p in pathlib.Path('temp').iterdir():
print(p)
# temp/file.txt
# temp/new_file.txt
# temp/new_file2.txt
# temp/dir
pathlibを使ったファイル・ディレクトリの作成や一覧の取得などについての詳細は以下の記事を参照。
- 関連記事: Python, pathlibでファイルの作成・open・読み書き・削除
- 関連記事: Python, pathlibでディレクトリ(フォルダ)の作成・削除
- 関連記事: Python, pathlibでファイル一覧を取得(glob, iterdir)
パスの移動: /演算子, joinpath(), parentなど
ディレクトリツリー内を移動するように、あるPath
オブジェクトを基準として別のディレクトリやファイルを示すPath
オブジェクトを生成できる。
パスの連結・追加
Path
オブジェクトに対して/
演算子を使うとパスが連結される。
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
joinpath()
メソッドでも同様にパスを連結できる。複数連結する場合は引数を複数指定する。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
親ディレクトリへの移動
..
の連結と相対パス・絶対パス
相対パス..
を連結すると親ディレクトリ(上位ディレクトリ)への移動となる。
p_dir = pathlib.Path('temp/dir')
p_file_join = p_dir.joinpath('..', 'file.txt')
print(p_file_join)
# temp/dir/../file.txt
パスが参照するファイルが同一か判定するsamefile()
メソッドで、..
を使わないPath
オブジェクトと同一のファイルを参照していることが確認できる。この場合、==
演算子はFalse
を返すので注意。
p_file = pathlib.Path('temp/file.txt')
print(p_file.samefile(p_file_join))
# True
print(p_file == p_file_join)
# False
..
を含む相対パスを絶対パスに変換するにはresolve()
メソッドを使う。resolve()
で絶対パスに変換すると==
もTrue
となる。
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
絶対パスを相対パスに変換するにはrelative_to()
メソッドを使う。引数に指定したパスを基準とする相対パスを返す。
Pythonが実行されている作業ディレクトリ(カレントディレクトリ)はcwd()
で取得できるので、絶対パスをカレントディレクトリからの相対パスに変換するには以下のようにする。
print(p_file_join.resolve().relative_to(pathlib.Path.cwd()))
# temp/file.txt
pathlibを使った相対パス・絶対パスの処理についての詳細は以下の記事を参照。
parent属性
親ディレクトリに移動するにはparent
属性を使う方法もある。
p_dir = pathlib.Path('temp/dir')
print(p_dir.parent)
# temp
print(p_dir.parent.joinpath('file.txt'))
# temp/file.txt
ただし、parent
は純粋な字句操作なので注意。元のオブジェクトが..
を含んでいる場合、特にそれらを解釈するわけではない。
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
上位階層に一気に移動できるparents
など、より詳細は以下の記事を参照。
with_name()メソッド
with_name()
メソッドを使うと、同じディレクトリ(同一階層)の別名のファイルのPath
を生成できる。親ディレクトリに移動して別のファイル名を連結するより簡単。
p_file = pathlib.Path('temp/file.txt')
print(p_file.with_name('new_file.txt'))
# temp/new_file.txt
拡張子を変更するwith_suffix()
など、より詳細は以下の記事を参照。
Pathオブジェクトを文字列(str)に変換
これまでの例のように、Path
オブジェクトをprint()
で出力するとパスの文字列が表示されるが、型自体はあくまでもPath
(PosixPath
またはWindowsPath
)で、文字列(str
)ではない。
p_file = pathlib.Path('temp/file.txt')
print(p_file)
# temp/file.txt
print(type(p_file))
# <class 'pathlib.PosixPath'>
文字列に変換したい場合はstr()
を使う。
s = str(p_file)
print(s)
# temp/file.txt
print(type(s))
# <class 'str'>
Path
のname
属性でファイル名を文字列で取得したり、suffix
属性で拡張子を文字列で取得したりすることもできる。
osモジュールの関数の引数にPathオブジェクトを指定
os.path
の関数の引数にはパスの文字列を指定するが、Python3.6以降、多くの関数でPath
オブジェクトも引数に指定できるようになった。
os.path.isfile()
を例とする。パス文字列でもPath
オブジェクトでも正しく動作する。
import os
print(os.path.isfile('temp/file.txt'))
# True
print(os.path.isfile(pathlib.Path('temp/file.txt')))
# True
Path
オブジェクトを引数に指定できるようになった関数には、その旨が公式ドキュメントに記載されている。
バージョン 3.6 で変更: path-like object を受け入れるようになりました。
os.path.isfile() — Python 3.12.0 ドキュメント
なお、上述のようにPath
オブジェクトにはos.path.isfile()
に対応するis_file()
メソッドがある。次に説明するようにos
の主な関数にはそれに対応するPath
オブジェクトのメソッドがあるので、あえてos
の関数を使う必要はあまりない。
osモジュールとpathlibモジュールの対応一覧
osモジュールの関数がpathlibモジュールのPath
およびPurePath
オブジェクトのどのメソッドに対応しているかの一覧表が公式ドキュメントに記載されている。
主なものは以下の通り。
処理内容 | os および os.path | pathlib |
---|---|---|
カレントディレクトリ取得 | os.getcwd() |
Path.cwd() |
先頭の~ をホームディレクトリに置換 |
os.path.expanduser() |
Path.expanduser() , Path.home() |
パスの存在確認 | os.path.exists() |
Path.exists() |
ディレクトリか判定 | os.path.isdir() |
Path.is_dir() |
ファイルか判定 | os.path.isfile() |
Path.is_file() |
シンボリックリンクか判定 | os.path.islink() |
Path.is_symlink() |
絶対パスか判定 | os.path.isabs() |
PurePath.is_absolute() |
絶対パスに変換 | os.path.realpath() |
Path.resolve() |
相対パスに変換 | os.path.relpath() |
PurePath.relative_to() |
ステータスを取得 | os.stat() |
Path.stat() , Path.owner() , Path.group() |
パスを連結 | os.path.join() |
PurePath.joinpath() |
ファイル名を取得 | os.path.basename() |
PurePath.name |
親ディレクトリを取得 | os.path.dirname() |
PurePath.parent |
拡張子を分割・取得 | os.path.splitext() |
PurePath.stem , PurePath.suffix |
ディレクトリを生成 | os.makedirs() |
Path.mkdir() |
ディレクトリを削除 | os.rmdir() |
Path.rmdir() |
ファイルを削除 | os.remove() , os.unlink() |
Path.unlink() |
それぞれのメソッドや属性の使い方の詳細は以下の記事を参照。