note.nkmk.me

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

Date: 2018-10-01 / tags: Python, ファイル操作

Pythonのpathlibモジュールを使うと、ファイル・ディレクトリ(フォルダ)のパスをオブジェクトとして操作・処理できる。

ファイル名・親ディレクトリの抽出やパス一覧の取得、ファイルの作成・削除など、一通りの処理が可能。慣れるとパスの文字列を利用する従来のosモジュールよりも使いやすい。

pathlibはPython3.4から追加されたモジュール。標準ライブラリに含まれているので追加のインストールは必要ない(importは必要)。

ここでは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オブジェクトを生成できる。引数にパスの文字列を指定する。相対パスでも絶対パスでもOK。

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()で出力するとパスの文字列が表示されるが、型自体はあくまでもParhPosixPathまたは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オブジェクトのどのメソッドに対応しているかの一覧表が公式ドキュメントに記載されている。

以下に処理内容を加えた上で転載する(順番も入れ替えている)。

処理内容 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() PurePath.suffix

それぞれのメソッドの使い方の例など、詳細は以下の記事を参照。

スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事