Python, pathlibの使い方(パスをオブジェクトとして操作・処理)

Pythonのpathlibモジュールを使うと、ファイル・ディレクトリ(フォルダ)のパスをオブジェクトとして操作・処理できます。 ファイル名・親ディレクトリの抽出やパス一覧の取得、ファイルの作成・削除など、一通りの処理ができます。慣れるとパスの文字列を利用する従来のos.pathよりも使いやすい。 pathlibはPython3.4から追加されたモジュール。標準ライブラリに含まれているので追加のインストールは必要ない(importは必要)。

pathlib --- オブジェクト指向のファイルシステムパス — Python 3.7.0 ドキュメント

ここではpathlibモジュールの基本的な使い方として、以下の内容について説明します。

Pathオブジェクトを生成・処理 コンストラクタpathlib.Path() メソッドの実行 存在しないパスに対する処理 パスの移動: /演算子, joinpath(), parent パスの連結・追加 親ディレクトリへの移動 Pathオブジェクトを文字列(str)に変換 osモジュールの関数の引数にPathオブジェクトを指定 osモジュールとpathlibモジュールの対応一覧

以下のようなファイル・ディレクトリ構成を例とします。 temp ├── dir │ └── sub_dir │ └── file2.txt └── file.txt

pathlibのより具体的な内容については以下の記事などを参照。

Pathオブジェクトを生成・処理

コンストラクタpathlib.Path()

pathlibモジュールではパスをオブジェクトとして操作します。 コンストラクタpathlib.Path()でPathオブジェクトを生成できます。引数にパスの文字列を指定します。相対パスでも絶対パスでも問題ありません。

import pathlib
import os
import pprint

p_file = pathlib.Path('temp/file.txt')

print(p_file)
# temp/file.txt

print(type(p_file))
# <class 'pathlib.PosixPath'>

例はMacで実行しているので、Macを含むUnix系OSのクラスであるPosixPath型のインスタンスが生成されます。Windowsで実行するとWindowsPath型となります。 UnixのマシンでWindowsのパスを扱いたいときや、逆にWindowsのマシンでUnixのパスを扱いたいときなどのような特別な場合は純粋パスのクラスであるPureWindowsPath型やPurePosixPath型のインスタンスを生成する必要があるが、実際のファイルやディレクトリを処理する場合はpathlib.Path()を使っておけば問題ない。 ディレクトリの場合も同じ。

p_dir = pathlib.Path('temp/dir')

print(p_dir)
# temp/dir

print(type(p_dir))
# <class 'pathlib.PosixPath'>

メソッドの実行

これらのオブジェクトからメソッドを呼ぶことで様々な処理が可能となります。例えばオブジェクトがファイルかどうかを判定するis_file()メソッドを実行する例は以下の通り。

print(p_file.is_file())
# True

print(p_dir.is_file())
# False

なお、ディレクトリかどうかを判定するメソッドはis_dir()。

存在しないパスに対する処理

存在しないパスのオブジェクトを生成することもできます。パスの存在を確認するメソッド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()を使うとファイルが新規作成されていることが確認できます。

pprint.pprint(list(pathlib.Path('temp').iterdir()))
# [PosixPath('temp/file.txt'),
#  PosixPath('temp/new_file.txt'),
#  PosixPath('temp/new_file2.txt'),
#  PosixPath('temp/dir')]

pathlibを使ったファイル・ディレクトリの作成や一覧の取得などについての詳細は

パスの移動: /演算子, joinpath(), parent

ディレクトリツリー内を移動するように、あるPathオブジェクトを基準として別のディレクトリやファイルを示すPathオブジェクトを生成することができます。

パスの連結・追加

Pathオブジェクトに対して/演算子を使うとパスが連結されます。

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_file_join = p_dir.joinpath('..', 'file.txt')

print(p_file_join)
# temp/dir/../file.txt

パスが参照するファイルが同一であるかを判定するsamefile()メソッドで確認すると、..を使わないPathオブジェクトと同一のファイルを参照していることが確認できます。この場合は==演算子では一致しないので気をつけてください。

print(p_file)
# temp/file.txt

print(p_file.samefile(p_file_join))
# True

print(p_file == p_file_join)
# False

..を含む相対パスを絶対パスに変換するにはresolve()メソッドを使います。resolve()で絶対パスに変換すると==でも一致します。

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

resolve()メソッドが返すのはPathオブジェクト。文字列ではない。

print(type(p_file.resolve()))
# <class 'pathlib.PosixPath'>

絶対パスを相対パスに変換するにはrelative_to()メソッドを使います。引数に指定したパスを基準とする相対パスを返します。 Pythonが実行されている作業ディレクトリ(カレントディレクトリ)はcwd()で取得できるので、絶対パスをカレントディレクトリからの相対パスに変換するには以下のようにします。

print(p_file_join.resolve().relative_to(pathlib.Path.cwd()))
# temp/file.txt

pathlibを使った相対パス・絶対パスの処理についての詳細は

親ディレクトリに移動する場合はparent属性を使う方法もあります。こちらのほうが分かりやすい。

print(p_dir.parent)
# temp

print(p_dir.parent.joinpath('file.txt'))
# temp/file.txt

parentは純粋な字句操作。元のオブジェクトが..を含んでいる場合、特にそれらを解釈するわけではないので気をつけてください。

print(p_file_join.parent)
# temp/dir/..

上位階層に一気に移動できるparentsについてなど、より詳細は

Pathオブジェクトを文字列(str)に変換

上の例のように、Path型のオブジェクトをprint()で出力するとパスの文字列が表示されるが、型自体はあくまでもParh(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'>

osモジュールの関数の引数にPathオブジェクトを指定

os.pathの各関数はパスの文字列を引数に指定して処理を行うが、Python3.6以降は多くの関数でPathオブジェクトも引数に指定できるようになりました。 os.path.isfile()を例とします。パス文字列でもPathオブジェクトでもどちらでも正しく動作します。

print(os.path.isfile('temp/file.txt'))
# True

print(os.path.isfile(p_file))
# True

Pathオブジェクトを引数に指定できるようになった関数はその旨が公式ドキュメントに記載されています。

バージョン 3.6 で変更: path-like object を受け入れるようになりました。 os.path.isfile() --- 共通のパス名操作 — Python 3.7.1rc1 ドキュメント

なお、上述のようにPathオブジェクトにはos.path.isfile()に対応するis_file()メソッドがあります。次に説明するようにosの主な関数にはそれに対応するPathオブジェクトのメソッドがあるので、あえてosの関数を使う必要はあまりない。

osモジュールとpathlibモジュールの対応一覧

osモジュールの関数がpathlibモジュールのPathオブジェクトのどのメソッドに対応しているかの一覧表が公式ドキュメントに記載されています。

pathlib --- オブジェクト指向のファイルシステムパス — Python 3.7.1rc1 ドキュメント

以下に処理内容を加えた上で転載する(順番も入れ替えている)。処理内容 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.abspath() Path.resolve() ステータスを取得 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()

Last Updated: 6/26/2019, 10:34:03 PM