[解決!Python]os.path.abspath関数で絶対パスを取得するには解決!Python

os.pathモジュールが提供するabspath関数で特定のパスの絶対パスを取得する方法や、その際に注意する点、pathlib.Path.absoluteメソッドとの振る舞いの違いなどを紹介する。

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

連載目次

from os import getcwd, chdir
from os.path import abspath, join, normpath, realpath, islink

# 現在の作業ディレクトリを基点とした絶対パスを取得
cwd = getcwd()
print(cwd)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0198/code
# Windows:C:\tmp\pytips\pytips_0198\code

p = abspath('foo.txt')
print(p)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0198/code/foo.txt
# Windows:C:\tmp\pytips\pytips_0198\code\foo.txt

tmp = normpath(join(getcwd(), 'foo.txt'))
print(tmp)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0198/code/foo.txt
# Windows:C:\tmp\pytips\pytips_0198\code\foo.txt
print(p == tmp)  # True

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

# シンボリックリンクを含むパスの絶対パスを取得
print(islink('dir1'))  # True
chdir('dir1')
print(getcwd())
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0198/code/dir0
# Windows:C:\tmp\pytips\pytips_0198\code\dir1

p = abspath('../dir1/cdir')
print(p)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0198/code/dir1/cdir
# Windows:C:\tmp\pytips\pytips_0198\code\dir1\cdir

# pathlibモジュールのPath.absoluteメソッドとは挙動が異なることがある
from pathlib import Path

path = Path('../dir1/cdir')
p = path.absolute()
print(p)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0198/code/dir0/../dir1/cdir
# Windows:C:\tmp\pytips\pytips_0198\code\dir1\..\dir1\cdir

# シンボリックリンクを含むパスから正規の絶対パスを取得
chdir(cwd)
p = realpath('dir1/cdir')
print(p)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0198/code/dir0/cdir
# Windows:C:\tmp\pytips\pytips_0198\code\dir0\cdir


os.path.abspath関数による絶対パスの取得

 os.pathモジュールが提供するabspath関数を使うと、その関数に指定したパスの絶対パスを取得できる。ここではmacOSとWindowsを例として、その使い方を見ていく。

 macOSでは次のようなディレクトリ階層を作成した。

macOSでサンプルとするディレクトリ階層 macOSでサンプルとするディレクトリ階層

 このうち、dir1ディレクトリはdir0ディレクトリに対するシンボリックリンクになっている。Windowsでも同様なディレクトリ階層を作成している。

Windowsでサンプルとするディレクトリ階層 Windowsでサンプルとするディレクトリ階層

 こちらでもdir1ディレクトリはdir0ディレクトリに対するシンボリックリンクになっている(管理者権限でコマンドプロンプトを実行し、「mklink /D」コマンドで作成)。

 また、osモジュールおよびos.pathモジュールから以下の関数をインポートした。

from os import getcwd, chdir
from os.path import abspath, join, normpath, realpath, islink


 Pythonのスクリプトを実行する作業ディレクトリはpytips_0198/codeディレクトリとする(後でディレクトリを移動する)。

cwd = getcwd()
print(cwd)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0198/code
# Windows:C:\tmp\pytips\pytips_0198\code


 macOSの出力結果は「/private/tmp/pytips/pytips_0198/code」となっているが、これは「/tmp/……」と読み替えてほしい(/tmpディレクトリが/private/tmpディレクトリへのシンボリックリンクになっているため)。

 既に述べたが、abspath関数は渡したパスの絶対パスを返す。簡単な例を以下に示す。

p = abspath('foo.txt')
print(p)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0198/code/foo.txt
# Windows:C:\tmp\pytips\pytips_0198\code\foo.txt


 ここではpytips_0198/codeディレクトリに存在しないファイルのパス「foo.txt」を渡しているが問題はない。この場合は、現在の作業ディレクトリ(os.getcwd関数で得られるパス)と、abspath関数渡したパスを連結したものが絶対パスとして戻される。

 os.path.abspath関数のドキュメントにもあるが、これはnormpath(join(getcwd(), 'foo.txt'))を呼び出したのと同じ結果になる。

tmp = normpath(join(getcwd(), 'foo.txt'))
print(tmp)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0198/code/foo.txt
# Windows:C:\tmp\pytips\pytips_0198\code\foo.txt
print(p == tmp)  # True


 ここで使っているnormpath関数とjoin関数についても簡単に見ておこう。join関数は1つ以上のパスを連結した結果を返す関数だ。ただし、渡した引数の中でルートとなる要素があった場合、その要素よりも前の要素については捨てられる点には注意しよう。以下に例を示す。

p = join('foo', 'bar')
print(p)
# 出力結果:
# macOS:foo/bar
# Windows:foo\bar

p = join('foo', '/bar', 'baz')
print(p)
# 出力結果:
# macOS:/bar/baz
# Windows:/bar\baz


 Windows環境では異なるドライブ文字を含んだ場合も同様にそれ以前の要素は無視される(以下の例では先頭の'foo'はCドライブのカレントディレクトリにある'foo'というパスを意味するが、次の要素が'd:bar'なので無視される。なお、このd:barはDドライブのカレントディレクトリにあるbarというパスを表すだけで、Dドライブのルートディレクトリにあるbarというパスを表しているわけではないことにも注意)。

p = join('foo', 'd:bar', 'baz')
print(p)  # d:bar\baz


 normpath関数はパスを正規化する関数だ。ここでいう「正規化」とはカレントディレクトリを表すドット「.」や親ディレクトリを表す2つのドット「..」などを解決したり、連続するスラッシュを単一のスラッシュとしたりする処理だと考えればよい。

p = normpath('foo//bar/../baz.txt')
print(p)
# 出力結果:
# macOS:foo/baz.txt
# Windows:foo\baz.txt


 この例ではfooとbarの間のダブルスラッシュが単一のスラッシュに変換されるとともに、親ディレクトリを意味する「..」が解決された結果、fooディレクトリの下にあるbaz.txtファイルを意味するパスが返された。

 normpath関数による正規化が行われるので、abspath関数に「..」を含むパスを与えるとそれが正規化されたものが返される。以下に例を示す。

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


 現在の作業ディレクトリは「/tmp/pytips/pytips_0198/code」ディレクトリなので、abspath関数に渡した「../../pytips_0197/pytips_0197.txt」というパスはcodeディレクトリの上の上のディレクトリ(pytipsディレクトリ)にあるpytips_0197ディレクトリにあるpytips_0197.txtファイルを意味し、実際にそのパスが得られている。

 パスの一部(ディレクトリ)にシンボリックリンクが含まれている場合には注意が必要になる。冒頭で述べたようにdir1ディレクトリはdir0ディレクトリに対するシンボリックリンクとなっている。これを例に見てみよう。

print(islink('dir1'))  # True
chdir('dir1')
print(getcwd())
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0198/code/dir0
# Windows:C:\tmp\pytips\pytips_0198\code\dir1


 この例ではos.path.islink関数でdir1ディレクトリがシンボリックリンクであることを確認し、そこに作業ディレクトリを移動している。macOSではその結果、リンク先であるdir0ディレクトリに移動したことが分かる(Windowsではdir1ディレクトリが得られている。OSによる挙動の異なりであり、シンボリックリンクを扱う場合には注意が必要になるかもしれない)。

 ここで親ディレクトリにあるdir1ディレクトリ(とは現在の作業ディレクトリのことだ)にあるcdirというパスの絶対パスを得てみよう。

p = abspath('../dir1/cdir')
print(p)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0198/code/dir1/cdir
# Windows:C:\tmp\pytips\pytips_0198\code\dir1\cdir


 「..」を含むパスが正規化され、ここではdir0という要素が出てくることなく、dir1を含むパスが得られた。これでも問題はないだろうが、シンボリックリンクを解決したパスが必要なときには以下で紹介するos.path.realpath関数を使う必要がある。また、正規化を含む振る舞いは、pathlibモジュールのPathクラスで同様な処理を行うPath.absoluteメソッドとは異なる点にも注意すること。以下は同じことをPath.absoluteメソッドで試した結果だ。

from pathlib import Path

path = Path('../dir1/cdir')
p = path.absolute()
print(p)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0198/code/dir0/../dir1/cdir
# Windows:C:\tmp\pytips\pytips_0198\code\dir1\..\dir1\cdir


 absoluteメソッドでは「..」が解決されずに、それを含んだままの絶対パスが戻されている。こちらの方が望ましい情報を含んでいるという場合には、abspath関数ではなく、Path.absoluteメソッドを使うのがよいだろう。

 最後にシンボリックリンクを含むパスから、それを解決した正規の絶対パスをrealpath関数で取得する例も示しておこう。

chdir(cwd)
p = realpath('dir1/cdir')
print(p)
# 出力結果:
# macOS:/private/tmp/pytips/pytips_0198/code/dir0/cdir
# Windows:C:\tmp\pytips\pytips_0198\code\dir0\cdir


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

解決!Python

Copyright© Digital Advantage Corp. All Rights Reserved.

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

注目のテーマ

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

RSSについて

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

メールマガジン登録

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