Python, pathlibで絶対パスと相対パスを相互変換・判定

Modified: | Tags: Python, ファイル処理

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のサブクラスなので、PathPosixPathまたは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

引数strictTrueとすると、パスが示すファイルやディレクトリが存在しない場合にエラーとなる。デフォルトは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

関連カテゴリー

関連記事