pathlibはPython3.4で標準搭載された、Pythonでファイルやディレクトリのパスを参照、検索、作成などの操作をするライブラリです。
パス操作は特定のタスクに限らず頻繁に使われるので、基本的な使い方を抑えておくことで仕事効率を向上できます。
pathlibの頻出機能
pathlibはPython3.4で標準搭載されているため、利用にあたってインストールの必要はなく、importしてすぐに利用できます。
ここでは、パスの探索/変更及び検索方法が一目でわかるように、一覧でよく使う機能を紹介します。
パスの参照/変更
ファイルバスとして、"/top_dir/data/001.png"を例としてpathlibの機能を説明します。
from pathlib import Path
file_path = Path('/top_dir/data/001.png') # pathlibオブジェクトでパスを取得
dir_path = file_path.parent # ファイルの親ディレクトリのパス(/top_dir/data/)
実行形式 | 結果 | 説明 |
---|---|---|
file_path.name | 001.png | ファイル名を取得 |
file_path.stem | 001 | 拡張子を除いたファイル名 |
file_path.suffix | .png | 拡張子を取得 |
file_path.with_name(name) | /top_dir/data/aaa.jpg ※ name=aaa.jpgとした場合 | file_pathからname部分を変更 |
file_path.with_stem(stem) | /top_dir/data/bbb.png ※ stem=bbbとした場合 | file_pathからstem部分を更新 |
file_path.with_suffix(suffix) | /top_dir/data/001.json ※ suffix=.jsonとした場合 | file_pathからsuffix部分を更新 |
file_path.parent | /top_dir/data | 親ディレクトリのパスを取得 |
file_path.parents[num] | /top_dir ※ num=1の場合 | numで指定した分の親ディレクトリのパスを取得 parets[0]はparent同じ結果になる。 |
file_path.relative_to(path) | data/001.png ※ path=/top_dir/とした場合 | pathからの相対パスを取得 |
file_path.resolve() | /top_dir/data/001.png ※ Path('001.png').resolve()の実行結果 | file_pathを絶対パスへ変換 |
dir_path.joinpath(name1, name2,…) | /top_dir/data/AAA/BBB ※ joinpath('AAA', 'BBB')とした場合 | 指定したnameを繋げたパスを作成 |
リファレンス: pathlib --- オブジェクト指向のファイルシステムパス
パスの一覧取得/検索
ここでは以下のディレクトリ構成を例として、パスの一覧取得(iterdir)、検索(glob)の概要を紹介します。
top_dir ├── config.yaml ├── data │ ├── 001.png │ ├── 002.png │ ├── 003.yaml │ └── sample.txt ├── readme.md └── src ├── lib │ └── utils.py └── main.py
機能 | 説明 |
---|---|
Path.iterdir() | ディレクトリ直下のパス一覧をイタレータとして取得。 注: Pathはディレクトリである必要がある |
Path.glob(pattern) | patternに一致するパスを検索する。 patternには正規表現も利用可 |
Path.rglob(pattern) | patternに一致するパスを再起的に検索する。 globに"**/"を付けて場合と同じ。 |
パスの一覧を取得: Path.iterdir()
Path.iterdir()は、指定されたパス直下のファイル/ディレクトリの一覧をイタレータとして取得します。
注意点として、iterdirではサブディレクトリまでは取得されない点です。(data配下は取得されていません。)
サブディレクトリまで取得したい場合は、後述のPath.glob()を用います。
top_dir = Path('./top_dir') # top_dirのパスを取得
print(type(top_dir.iterdir())) # <class 'generator'>
for文を使ってイタレータを出力してみます。
# iterdirの参照
for path in top_dir.iterdir():
print(path)
### 実行結果
# top_dir/config.yaml
# top_dir/readme.md
# top_dir/data
# top_dir/src
top_dir直下のファイル/ディレクトリが参照されているのが分かります。
iterdirは、Pathがファイルを指している場合はNotADirectoryErrorとなります。
config_file = Path('./top_dir/config.yaml')
for path in config_file.iterdir():
print(path)
### 実行結果
# NotADirectoryError: [Errno 20] Not a directory: 'top_dir/config.yaml'
パスの検索: Path.glob()
Path.glob()は、指定したパターンに一致するパスを検索します。検索には任意の文字列を意味するアスタリスク(*)などのワイルドカードが利用できます。また、iterdirと異なりサブディレクトリ配下を含めた再起的な検索も可能です。
top_dir = Path('./top_dir') # top_dirのパスを取得
# top_dir直下の全てのファイル/ディレクトリを検索
for path in top_dir.glob('*'):
print(path)
### 実行結果
# top_dir/config.yaml
# top_dir/readme.md
# top_dir/data
# top_dir/src
サブディレクトリも含めて検索したい場合は、検索パターンに"**/"を追加します。
もしくはglobの代わりにrglobを用いても同じ結果が得られます。
# top_dir以下の.pngファイルを再起的に検索
for path in top_dir.glob('**/*.png'): # top_dir.rglob('*.png')でも同じ
print(path)
### 実行結果
# top_dir/data/002.png
# top_dir/data/001.png
検索結果をリストとして取得したい場合は、内包表記が使えます。
また、検索結果をソートして取得したい場合は組み込み関数のsortedが使えます。
list_png = [path for path in top_dir.glob('**/*.png')] # .pngファイルのリスト
print(list_png)
### 実行結果
# [PosixPath('top_dir/data/002.png'), PosixPath('top_dir/data/001.png')]
# 昇順にソートする場合
sorted(list_png) # 降順にする場合は、reverse=Trueを指定。
### 実行結果
[PosixPath('top_dir/data/001.png'), PosixPath('top_dir/data/002.png')]
ファイルやディレクトリのみを検索したい場合は、Path.is_file(), Path.is_dir()が使えます。
list_file = [path for path in top_dir.glob('**/*') if path.is_file()] # ファイルのみ
print(list_file)
### 実行結果
# [PosixPath('top_dir/config.yaml'), PosixPath('top_dir/readme.md'), 〜〜略〜〜 PosixPath('top_dir/src/lib/utils.py')]
list_dir = [path for path in top_dir.glob('**/*') if path.is_dir()] # ディレクトリのみ
print(list_file)
### 実行結果
# [PosixPath('top_dir/data'), PosixPath('top_dir/src'), PosixPath('top_dir/src/lib')]
ファイルを開く:Path.open()
ファイルを開くときはopenメソッドが使えます。使い方は、組み込み関数のopenと同じように読み込み/書き込みのモードを指定して使います。
# ファイル操作
sample_file = Path('./top_dir/data/sample.txt')
# ファイルへ書き込み
with sample_file.open('w') as f:
f.write('hello pathlib world\n')
# ファイルを読み込み
with sample_file.open('r') as f:
buf = f.read()
print(buf) # 実行結果: hello pathlib world
存在しないファイルを開こうとするとFileNotFoundErrorとなるため、ファイルが存在する場合だけopenしたいときはexistsメソッドが使えます。existsメソッドはPathが既存のファイルかディレクトリを指している場合にTrueを返します。
existsメソッドを使って、ファイルが存在する場合だけopenを実行する方法は次のとおりです。
sample_file = Path('./top_dir/data/not_exists_file.txt')
if sample_file.exists(): # ファイルが存在する場合
with sample_file.open('r') as f:
buf = f.read()
print(buf)
コメント