Python, pathlibで絶対パスと相対パスを相互変換・判定
Pythonのpathlibモジュールを使って絶対パスと相対パスを相互に変換したり判定したりする方法を説明する。
pathlibの基本的な使い方については以下の記事を参照。
本記事のサンプルコードでは以下のようにpathlibモジュールからPath
クラスをインポートしている。pathlibは標準ライブラリに含まれているので追加のインストールは不要。
from pathlib import Path
絶対パスと相対パス
はじめに絶対パスと相対パスについて簡単に説明する。
Wikipedia英語版に具体的な例を含む説明がある。
絶対パス(absolute path)
絶対パスは、ファイルやディレクトリを一意に示すパス。
Macを含むUnix系OSでは/
から始まり、Windowsではドライブ文字や\\
(サーバーの場合)から始まる。
- Unix(Mac含む):
/Users/xxx/Documents/
- WIndows:
C:\Program Files
or\\servername\
相対パス(relative path)
相対パスは、あるディレクトリ(カレントディレクトリ)からの相対的な位置を示すパス。カレントディレクトリによって同じファイルやディレクトリでも異なるパスで表される。
例えば、/Users/xxx/Documents/file.txt
というファイルの相対パスは以下のように表される。
/Users/
をカレントディレクトリとした場合xxx/Documents/file.txt
/Users/xxx/
をカレントディレクトリとした場合Documents/file.txt
相対パスでは現在のパスを明示的に示す.
や、一つ上の階層を示す..
などが使える。
/Users/xxx/Documents/
をカレントディレクトリとした場合、..
は/Users/xxx/
に相当する。
pathlibの基本
Path()
でPath
オブジェクトを生成して操作する。引数に相対パスまたは絶対パスを文字列で指定する。
p = Path('dir/sub_dir/file.txt')
print(p)
# dir/sub_dir/file.txt
print(type(p))
# <class 'pathlib.PosixPath'>
OSによってPosixPath
またはWindowsPath
のインスタンスが生成される。
なお、以降では純粋パスPurePath
のメソッドも紹介するが、具象パスPath
は純粋パスPurePath
のサブクラスなので、Path
(PosixPath
またはWindowsPath
)のインスタンスからでも使用可能。
詳しくは以下の記事を参照。
カレントディレクトリを取得: cwd()
Path
のクラスメソッドであるcwd()
でカレントディレクトリの絶対パスのPath
オブジェクトを取得できる。
print(Path.cwd())
# /Users/mbp/Documents/my-project/python-snippets/notebook
print(type(Path.cwd()))
# <class 'pathlib.PosixPath'>
Path
のインスタンスからもcwd()
を呼べるようになっている。
p = Path('dir/sub_dir/file.txt')
print(p.cwd())
# /Users/mbp/Documents/my-project/python-snippets/notebook
print(type(p.cwd()))
# <class 'pathlib.PosixPath'>
同じくカレントディレクトリを返すos.getcwd()
はパスを文字列(str
)で返す。
import os
print(os.getcwd())
# /Users/mbp/Documents/my-project/python-snippets/notebook
print(type(os.getcwd()))
# <class 'str'>
pathlibにはカレントディレクトリを変更するメソッドはない。os.chdir()
を使う。os.chdir()
の引数にはPath
オブジェクトをそのまま指定可能。
相対パスを絶対パスに変換: resolve(), absolute()
resolve()
相対パスを絶対パスに変換するにはresolve()
を使う。Path
オブジェクトが返される。
p = Path('dir/sub_dir/file.txt')
print(p.resolve())
# /Users/mbp/Documents/my-project/python-snippets/notebook/dir/sub_dir/file.txt
相対パスに..
が含まれている場合、正しく解釈された上で除去されて絶対パスに変換される。
p_rel = Path('dir/sub_dir/../file.txt')
print(p_rel)
# dir/sub_dir/../file.txt
print(p_rel.resolve())
# /Users/mbp/Documents/my-project/python-snippets/notebook/dir/file.txt
引数strict
をTrue
とすると、パスが示すファイルやディレクトリが存在しない場合にエラーとなる。デフォルトはstrict=False
。
p_new_file = Path('data/new_file.txt')
print(p_new_file.resolve())
# /Users/mbp/Documents/my-project/python-snippets/notebook/data/new_file.txt
# print(p_new_file.resolve(strict=True))
# FileNotFoundError: [Errno 2] No such file or directory: 'data/new_file.txt'
例は省略するが、resolve()
はシンボリックリンクも解決する。
absolute()
absolute()
も相対パスを絶対パスに変換する。Path
オブジェクトが返される。
p = Path('dir/sub_dir/file.txt')
print(p.absolute())
# /Users/mbp/Documents/my-project/python-snippets/notebook/dir/sub_dir/file.txt
absolute()
はresolve()
と異なり..
を除去しない。
p_rel = Path('dir/sub_dir/../file.txt')
print(p_rel.absolute())
# /Users/mbp/Documents/my-project/python-snippets/notebook/dir/sub_dir/../file.txt
absolute()
には引数strict
はなく、シンボリックリンクも解決しない。
絶対パスを相対パスに変換: relative_to()
以下の絶対パスを表すPath
オブジェクトを例とする。
p_abs = Path('dir/sub_dir/file.txt').resolve()
print(p_abs)
# /Users/mbp/Documents/my-project/python-snippets/notebook/dir/sub_dir/file.txt
絶対パスを相対パスに変換するにはrelative_to()
を使う。
引数に指定したパスを起点とする相対パスに変換される。
カレントディレクトリを起点とする相対パスに変換したい場合は上述のcwd()
を使う。
print(p_abs.relative_to(Path.cwd()))
# dir/sub_dir/file.txt
引数はPath
オブジェクトではなくパスの文字列でも指定可能。
print(p_abs.relative_to('/Users/mbp/Documents/my-project'))
# python-snippets/notebook/dir/sub_dir/file.txt
ルートやドライブが異なっているなど、変換が不可能なディレクトリを引数に指定するとエラーとなる。
# print(p_abs.relative_to('/usr/'))
# ValueError: '/Users/mbp/Documents/my-project/python-snippets/notebook/dir/sub_dir/file.txt' is not in the subpath of '/usr' OR one path is relative and the other is absolute.
便宜上、絶対パスを相対パスに変換と書いたが、相対パスを別のパスを起点とする相対パスに変換することもできる。
p = Path('dir/sub_dir/file.txt')
print(p.relative_to('dir'))
# sub_dir/file.txt
絶対パスか判定: is_absolute()
Path
オブジェクトが絶対パスかを判定するにはis_absolute()
を使う。
p_abs = Path('dir/sub_dir/file.txt').resolve()
print(p_abs)
# /Users/mbp/Documents/my-project/python-snippets/notebook/dir/sub_dir/file.txt
print(p_abs.is_absolute())
# True
is_absolute()
がFalse
であれば絶対パスではなく相対パス。
p = Path('dir/sub_dir/file.txt')
print(p.is_absolute())
# False
なお、Python 3.9で追加されたis_relative_to()
は現在のパスが引数に指定したパスからの相対パスとして表せるか(relative_to()
を実行できるか)を判定するもので、相対パスかどうかを判定するものはない。
print(p_abs.is_relative_to(Path.cwd()))
# True
print(p.is_relative_to(Path.cwd()))
# False
print(p.is_relative_to('dir/sub_dir'))
# True