[解決!Python]pathlib.Path.absolute/resolveメソッドで絶対パスを取得するには解決!Python

pathlibモジュールが提供するPathクラスのabsoluteメソッドとresolveメソッドはどちらも絶対パスを得るためのものである。その違いや使い分けについて紹介する。

» 2024年10月15日 05時00分 公開
[かわさきしんじDeep Insider編集部]
「解決!Python」のインデックス

連載目次

import os
from pathlib import Path

d = Path.cwd()  # d = os.getcwd()
print(d)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0199
# Windows:

# カレントディレクトリを基点とした相対パスを取得
p = Path('foo.txt').absolute()
print(p)  # /private/tmp/pytips/pytips_0199/foo.txt
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0199/foo.txt
# Windows:C:\tmp\pytips\pytips_0199
print(type(p))
# 出力結果:
# macOS:<class 'pathlib.PosixPath'>/<class 'pathlib._local.PosixPath'>
# Windows:<class 'pathlib.WindowsPath'>/<class 'pathlib._local.WindowsPath'>

# Path.absoluteメソッドは「..」やシンボリックリンクなどを解決しないまま返す
p = Path('dir0/../pytips_0199.txt').absolute()
print(p)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0199/dir0/../pytips_0199.txt
# Windows:C:\tmp\pytips\pytips_0199\dir0\..\pytips_0199.txt

# Path.resolveメソッドは「..」やシンボリックリンクを解決する
p = p.resolve()
print(p)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0199/pytips_0199.txt
# Windows:C:\tmp\pytips\pytips_0199\pytips_0199.txt

# シンボリックリンクの解決
Path('dir1').is_symlink()  # True

p = Path('dir1/foo.txt').absolute()
print(p)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0199/dir1/foo.txt
# Windows:C:\tmp\pytips\pytips_0199\dir1\foo.txt

os.chdir('dir1')
p = Path('foo.txt').absolute()
print(p)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0199/dir0/foo.txt
# Windows:C:\tmp\pytips\pytips_0199\dir1\foo.txt

os.chdir('..')

p = Path('dir1/foo.txt').resolve()
print(p)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0199/dir0/foo.txt
# Windows:C:\tmp\pytips\pytips_0199\dir0\foo.txt


 以下では次のようなディレクトリ階層でpytips_0199ディレクトリが現在の作業ディレクトリとなっているものとする。macOSでは/tmp/pytipsディレクトリ以下に次のようなディレクトリ階層を作成した。dir1ディレクトリはdir0ディレクトリへのシンボリックリンクとなっている。

macOSでのサンプルのディレクトリ階層 macOSでのサンプルのディレクトリ階層

 WindowsではC:\tmp\pytipsディレクトリ以下に次のようなディレクトリ階層を作成した。

Windowsでのサンプルのディレクトリ階層 Windowsでのサンプルのディレクトリ階層

 macOSのサンプルディレクトリ階層と同様、dir1ディレクトリはdir0ディレクトリへのシンボリックリンクとなっている(管理者権限でコマンドプロンプトを開き「mklink /D dir1 dir0」コマンドで作成)。

 また、事前にosモジュールをインポートし、pathlibモジュールからPathクラスもインポートしておく。

import os
from pathlib import Path

d = Path.cwd()  # d = os.getcwd()
print(d)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0199
# Windows:C:\tmp\pytips\pytips_0199


 macOSでのPath.cwdクラスメソッドの出力結果を見ると、「/tmp/…‥」ではなく「/private/tmp/…‥」となっているのは/tmpが/private/tmpへのシンボリックリンクとなっているからなので、以降ではこれを/tmpと読み替えてほしい。

pathlib.Path.absoluteメソッドによる絶対パスの取得

 pathlibモジュールにはファイルパスを表すPathクラス(とその具象クラス)があり、そのメソッドとしてパス関連の機能が用意されている。現在の作業ディレクトリを基点として、特定のパスの絶対パスを取得するにはそれらのうちのabsoluteメソッドを使用する。

 以下にシンプルな例を示す。

p = Path('foo.txt').absolute()
print(p)  # /private/tmp/pytips/pytips_0199/foo.txt
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0199/foo.txt
# Windows:C:\tmp\pytips\pytips_0199


 ここではfoo.txtというパスを表すオブジェクトを作成し、absoluteメソッドを呼び出している(現在の作業ディレクトリにはこのファイルは存在しないが、抽象的なパス操作をしている分には問題はない)。これにより、現在の作業ディレクトリを基点としたfoo.txtの絶対パスが返される。

 返されるのはPathクラス(の具象クラス)のオブジェクトである(os.pathモジュールの関数は文字列を返す)。

print(type(p))
# 出力結果:
# macOS:<class 'pathlib.PosixPath'>/<class 'pathlib._local.PosixPath'>
# Windows:<class 'pathlib.WindowsPath'>/<class 'pathlib._local.WindowsPath'>


 なお、2024年10月9日の時点では、Python 3.13.0環境でこれを実行すると、pathlib._local.PosixPathやpathlib._local.WindowsPathのように「_local」を間に含むようになる(Python 3.13ではpathlibモジュールに手が加えられた結果と思われる)。

 Path.absoluteメソッドは自身のパスに現在のディレクトリを表すドット「.」や親ディレクトリを表す「..」、シンボリックリンクなどが含まれていても、それらを解決しない点には注意しよう。以下に例を示す。

p = Path('dir0/../pytips_0199.txt').absolute()
print(p)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0199/dir0/../pytips_0199.txt
# Windows:C:\tmp\pytips\pytips_0199\dir0\..\pytips_0199.txt


 この例ではカレントディレクトリの下にあるdir0ディレクトリ、dir0の親ディレクトリを示す「..」、最後にpytips_0199.txtという3つの要素で構成されるパスを表すPathオブジェクトを作成して、absoluteメソッドを呼び出している。このとき、「..」が解決されていれば、得られる絶対パスは「/private/tmp/pytips/pytips_0199/pytips_0199.txt」「C:\tmp\pytips\pytips_0199\pytips_0199.txt」のようになるが、実際に得られるのは「..」入りのパスとなる。

 このようなパスから「..」などを削除して、シンボリックリンクを解決した絶対パスを得たいのであれば、Path.resolveメソッドを使用する。以下は「..」を含むパスからそれを削除する例だ。

p = p.resolve()
print(p)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0199/pytips_0199.txt
# Windows:C:\tmp\pytips\pytips_0199\pytips_0199.txt


 次にシンボリックリンクを解決する例も見ておこう。既に述べた通り、dir1ディレクトリはdir0ディレクトリへのシンボリックリンクである。そのため、そのパスに対して、Path.is_symlinkメソッドを呼び出すとTrueが返される。

Path('dir1').is_symlink()  # True


 このシンボリックリンクを含むPath('dir1/foo.txt')というパスに対して、absoluteメソッドを呼び出すと次のようになる。

p = Path('dir1/foo.txt').absolute()
print(p)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0199/dir1/foo.txt
# Windows:C:\tmp\pytips\pytips_0199\dir1\foo.txt


 macOSでもWindowsでもシンボリックリンクは解決されずに、そのままdir1として絶対パスが返されている。

 この状態で、dir1ディレクトリに移動して、そこにあるfoo.txtファイルを指すパスであるPath('foo.txt')でabsoluteメソッドを呼び出したのが以下だ。

os.chdir('dir1')
p = Path('foo.txt').absolute()
print(p)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0199/dir0/foo.txt
# Windows:C:\tmp\pytips\pytips_0199\dir1\foo.txt


 macOSではdir1ではなく、dir0が絶対パスに含まれるようになった。Windowsではシンボリックリンクであるdir1が絶対パスに含まれたままとなる(プラットフォームごとの挙動の異なり)。

 ここで、ディレクトリを元に戻して、Path('dir1/foo.txt')というパスに対してresolveメソッドを呼び出すと、今度はシンボリックリンクが解決され、dir0を含む絶対パスが(macOSでもWindowsでも)取得できた。

os.chdir('..')

p = Path('dir1/foo.txt').resolve()
print(p)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0199/dir0/foo.txt
# Windows:C:\tmp\pytips\pytips_0199\dir0\foo.txt


 普段はabsoluteメソッドで絶対パスを取得すればよいだろうが、パスの正規化(「..」の削除など)が必要になったり、シンボリックリンクを解決したりする必要があるときにはresolveメソッドを呼び出す必要がある。

「解決!Python」のインデックス

解決!Python

Copyright© Digital Advantage Corp. All Rights Reserved.

スポンサーからのお知らせPR

注目のテーマ

AI for エンジニアリング
「サプライチェーン攻撃」対策
1P情シスのための脆弱性管理/対策の現実解
OSSのサプライチェーン管理、取るべきアクションとは
Microsoft & Windows最前線2024
システム開発ノウハウ 【発注ナビ】PR
あなたにおすすめの記事PR

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。