pathlibモジュールが提供するPathクラス、PurePathクラスなどを使って、ファイルやディレクトリを扱う方法を紹介する。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
前回はosモジュールとos.pathモジュールを使用してのファイル/ディレクトリ操作の基本を見た。今回はPython 3.4で導入された比較的新しいpathlibモジュールを使って、同様な操作を行う方法を見てみよう。簡単なファイルの読み書きもサポートしているので、覚えておくと便利に使えるかもしれない。
Python 3.4で導入されたpathlibモジュールは、PythonでUNIXやWindowsのファイルやディレクトリ(のパス)を扱うためのものだ。UNIXとWindowsではパスの表記が異なることから(例えば、区切り文字、ドライブ文字の有無など)、pathlibモジュールではそれらを適切に扱えるような仕組みを用意している。
まず、pathlibモジュールでは「純粋パス」と「具象パス」を表すクラスを3つ定義している。
「純粋パス」というのは、実際にはOSのファイルシステムへのアクセスを行わない(実際にファイルやディレクトリにアクセスしようとして例外が発生することがない)。そのため、UNIX系のOSでWindows上のパス操作の確認などを行いたいときなどに使用できる。
これに対して、「具象パス」とは実際にPythonのコードを実行している環境に合わせて、OSレベルのシステムコールが実行されることもある。「具象パス」についてもpathlibモジュールでは以下の3つのクラスが定義されている。
実際のクラス階層は次のようになっている。
PurePath以下の純粋パスクラスは論理的なパスを扱うための機能を提供し、それらから派生する具象パスクラスは実際のファイルシステムへのアクセスを担うと考えるとよいだろう。純粋パスクラスは、パスを文字列のようなものとして捉え、拡張子の取り出しやパスの分割など、ファイルシステムを扱う際にあると便利な操作をメソッドや属性として用意したものとしても考えられる。これに対して、具象パスは実際のファイルシステム上に存在しているパス(ファイルやディレクトリ)を扱うための機能を提供する(例えば、ファイルが存在するかどうかを調べたり、ファイルの内容を読み出したり、ファイルに書き込みをしたりする機能がある)。
実際には、PurePathクラスのインスタンスとPathクラスのインスタンスを生成すると、そのときに実行環境に合わせたクラスのインスタンスが生成される。例えば、以下のコードを実行して、UNIX系のOS上でPathクラスのインスタンスを生成すれば、実際にはPosixPathクラスのインスタンスとなり、同じコードをWindows上で実行すればWindowsPathクラスのインスタンスが生成される。
from pathlib import Path
mypath = Path('.')
print(type(mypath))
このコードを、本連載で使用している「Try Jupyter」ページからたどれるJupyter Notebook環境で実行すると次のようになる。
このようにPathクラスのインスタンスではなく、PosixPathクラスのインスタンスが生成されている。一方、Windows上でローカルに起動したJupyter Notebook環境では次のようになる。
こちらではWindowsPathクラスのインスタンスが生成された。Pathクラスを介することで、コード上ではそれを実行する環境を抽象化しておいて、実際にコードを実行する(パスを操作する)ときには環境に応じた具体的なクラスのインスタンスが得られるようになっているということだ(これは、純粋パスについても同様だ)。
このようにして作成したパスは、以下で紹介していく各種の属性やメソッドを使って操作することもできるが、以下のように除算演算子「/」を使って、パスを連結することも可能だ。
mypath = Path('foo')
newpath = mypath / 'bar' / Path('baz')
print(newpath)
以下に実行結果を示す。
なお、PurePathクラスやPathクラスのインスタンスは多くの場合、前回見たosモジュールやos.pathモジュールの引数としても指定できる。PurePathクラスやPathクラスのインスタンスを受け取ることができるものについては、Pythonのドキュメント「os --- 雑多なオペレーティングシステムインタフェース」などを参照されたい。ドキュメント中で「バージョン 3.6 で変更: os.PathLike インタフェースを実装したオブジェクトを受け入れるようになりました」とあるものがそうだ。
実際のパス操作の話をする前に、PurePathクラスで定義されている属性やメソッドについて簡単にまとめておこう。以下にPurePathクラスで定義されている属性とメソッドを示す(一部。また、属性およびメソッド名の前の「PurePath.」は省略する)。
属性/メソッド | 説明 | 対応するos.pathモジュールの関数 |
---|---|---|
parts | パスを構成要素に分割したもの(タプル) | os.path.split関数 |
drive | ドライブ文字 | os.path.splitdrive(path)[0] |
root | インスタンスが絶対パスを表している場合には、そのルートの文字列 | |
anchor | ドライブ文字とルートを結合したもの | |
parent | そのパスの上位パス | os.path.dirname関数 |
name | パスの末尾(ファイル名もしくはディレクトリ名) | os.path.basename関数 |
suffix | パスの末尾の要素に含まれる拡張子 | os.path.splitext関数 |
suffixes | パスの末尾の要素に含まれる複数の拡張子を要素とするリスト(tar.gzが拡張子であれば['.tar', '.gz']のようになる) | |
stem | パスの末尾の要素から拡張子を取り除いたもの | |
as_posix() | パスをPOSIX形式に変換する(ディレクトリの区切りをスラッシュ「/」とした表現にする) | |
as_uri() | パスをfile URI形式に変換する(相対パスを渡すと例外になる。Windowsではドライブ文字も必要になるので注意すること) | |
is_absolute() | パスが絶対パスか相対パスかを調べる | os.path.isabs関数 |
joinpath(*others) | パスを、*othersに与えたパスと結合する | os.path.join関数 |
match(pattern) | パスが、patternに与えたパターンにマッチするかを調べる | |
relative_to(*other) | パスから、*otherに与えたパスへの相対パスを取得する | |
with_name(name) | パスのname属性を、nameに与えた名前に変えたパスを取得する | |
with_suffix(suffix) | パスの拡張子を、suffixに与えたものに変更したパスを取得する | |
PurePathクラスで定義されている属性/メソッド(一部) |
PurePathクラスの属性とメソッドは論理的なパスを操作するためのものに留まっている。とはいえ、複数の構成要素(複数のディレクトリとファイル)からなるパスを分割するような単純なものから、with_nameメソッドのように、既存の名前を別の名前に置き換えたパスを取得するなど、ファイルやディレクトリの名前を一括して変更するときに便利に使えるようなものまで用意されている。また、os.pathモジュールに含まれている機能に対応しているものもある。
幾つかの利用例を以下に示す。
from pathlib import PurePath
import os
abspath = PurePath('/foo/bar/baz.txt') # 絶対パス
relpath = PurePath('xxx/yyy/zzz.txt') # 相対パス
print('type:', type(abspath)) # 実行する環境によって変化する
print('parts:', abspath.parts) # 構成要素に分割
print('root:', abspath.root) # ルートを表示
print('root:', relpath.root) # ルートを表示(相対パスの場合)
print('parent:', abspath.parent) # 上位パスの表示
print('name:', relpath.name) # ファイル名
print('name:', os.path.basename('xxx/yyy/zzz.txt')) # os.pathモジュールを使用
print('suffix:', abspath.suffix) # 拡張子
print('stem:', abspath.stem) # 拡張子以外のファイル名
print('stem + suffix:', abspath.stem + abspath.suffix) # ファイル名全体
print('uri:', abspath.as_uri()) # URI形式(Windowsでは例外が発生するので注意)
print('is absolute:', relpath.is_absolute()) # 相対パスを「絶対パスか」調べる
print('joinpath:', Path('foo/bar').joinpath('baz', 'qux')) # パスを結合
print('with name:', relpath.with_name('qux.txt')) # ファイル名を置き換え
実行すると、次のようになる。コメントと合わせて見ながら、動作を確認してほしい。
なお、Windows上で実行しているJupyter Notebook環境ではas_uriメソッドの呼び出しで例外が発生する。これはabspath変数の値が「/foo/bar/baz.txt」となっていて、Windowsにおける絶対パスとは異なるためだ。Windows上で実行している人は「c:/foo/bar/baz.txt」などに変更してみてほしい。
これらの属性とメソッドは、PurePathクラスから派生している3つの具象パスクラスでも利用できる。というわけで、次に具象パスクラスについて見ていこう。
Copyright© Digital Advantage Corp. All Rights Reserved.