自分は今までpythonでファイル操作を行うときはos.pathとかglobとかを使っていたが、pathlibという優秀なものがあると聞いて使ってみた。
python3.4以降なら使わない手はない。
以下優れている点
- os, glob の組み合わせで行ってきた操作が大体pathlib一つでできるようになる
- メソッドチェーン的に記述でき、可読性が上がる
open()
などのファイル読み込み系の操作と親和性が高い- windowsだとファイルパスにエスケープ二つ
\\
入れる必要があるが、/
区切りで解釈してくれる
以下もうひとつな点
- 一部ライブラリではPathオブジェクトを受け付けず、
str()
でキャストする必要がある copy
など一部未対応のメソッドがある
公式ドキュメントはこちら
主な使用方法
import, インスタンス生成
基本はPath オブジェクトを生成して操作することになる。
インスタンス生成時にファイルまたはディレクトリのパスを指定する。(絶対パスでも相対パスでもよい)
>>> from pathlib import Path >>> p = Path('aaa/bbb/ccc.txt')
pはPath
のサブクラスであり、windowsならWindowsPath
、linux, maxならPosixPath
オブジェクトとなる。
使い方はほぼ同じなので気にする必要はない。
引数を指定しないとカレントディレクトリのリンクが自動的にパスに入る。
>>> Path()
WindowsPath('.')
カレントディレクトリ、ホームディレクトリ取得
# カレントディレクトリ取得 >>> p.cwd() # ホームディレクトリ取得 >>> p.home()
上記メソッドは新たなパスが格納されたPathオブジェクトを返す。
これに限らず、Path
オブジェクトのメソッドは新たなPath
を返すため、文字列を直に操作する必要がなくなる。
また、上記メソッドの出力はインスタンス生成時の引数に依らず、常に同じである。
Path
オブジェクトならいつでもカレント、ホームディレクトリを呼び出せる。
絶対パス取得
まずは絶対パスを取得する。
# シンボリックリンクを解決して絶対パスを返す >>> p = Path('.') >>> p.resolve() WindowsPath('D:/project/path_test') # なんかこっちでもいけるっぽい >>> p.absolute()
公式ドキュメントには書いてなかったが、p.absolute()
でも同じことができるっぽい。内部では同じメソッドを呼び出しているのだろうか。
コードの中身を見てないのでわかりません。
ついでに絶対パスかどうかの確認
>>> p.is_absolute()
True
絶対パスならTrueを返す。
ファイル名、拡張子の取得
ファイルまでのパスがPath
オブジェクトに入っているなら以下でファイル名を取得できる
拡張子や、拡張子を除いた名前部分(stem)を取得することもできる。戻り値は文字列なので注意
# ファイル名取得 戻り値は文字列 >>> p.name 'aaa.txt' # 拡張子取得 戻り値は文字列 >>> p.suffix '.txt' # .tar.gzみたいなのは.suffixes でリスト取得できる >>> p.suffixes ['.tar', '.gz'] # 拡張子を除いたファイル名を取得 戻り値は文字列 >>> p.stem 'aaa'
ファイル、ディレクトリ削除、権限変更
パスがファイルかディレクトリかでメソッドが変わる。
# ファイル削除 >>> p.unlink() # ディレクトリ削除 ただし空ディレクトリに限る >>> p.rmdir() # 権限変更 ファイル、ディレクトリ問わず適用可能 >>> p.chmod(755) >>> p.cwd(755)
ディレクトリが空じゃない場合はおとなしくshutil.rmtree
とかを使う。
パス結合
これが一番便利かもしれない。
Path
オブジェクトでは/
演算子がパスの結合として再定義されている。
# Pathオブジェクトに文字列で除算するとパス結合されたPathオブジェクトが返る >>> Path('a/b/c') / 'd' WindowsPath('a/b/c/d') # windowsでのエスケープ二つと混ぜても同じ結果が得られる >>> Path('a\\b\\c') / 'd' WindowsPath('a/b/c/d') # 一応メソッドもある >>> Path('a/b/c').joinpath('d') WindowsPath('a/b/c/d')
ファイル検索
指定したパス内のファイル、ディレクトリを検索できる。
使い方は標準ライブラリのglob
とほぼ同じである。
ただし、メソッドの戻り値はジェネレータであることに注意する。
# パス内の.py ファイルを検索、ジェネレータを返す >>> p.glob('*.py') <generator object Path.glob at 0x000002804AEC6C50> # リストとして取り出したければキャストする >>> list(p.glob('*.py')) # パス以下を再帰的に検索したい場合は以下のように指定する >>> p.glob('**/*.py')
ファイルを開く
Path
オブジェクトにはファイルを開くメソッドも用意されている。
テキストとして開くならこれで問題ない。当然だがパスはファイルが指定されている必要がある。
# ファイルを開く >>> f = p.open('r') # 組み込み関数にPathオブジェクトを渡すこともできる >>> f = open(p, 'r')
注意すべきは、Pathオブジェクトに対応していない外部ライブラリも存在するということ。
ここによると、どうやらopenCVのcv2.imread
には対応していないらしい。
そんな時は文字列にキャストしてからライブラリに渡せば問題ない。
>>> p = Path('aaa/bbb/ccc.txt') # str()でキャストできる UNIX環境 >>> str(p) 'aaa/bbb/ccc.txt' # windows 環境でも使える >>> str(p) 'aaa\\bbb\\ccc.txt # .as_posix()でもできるが、windows環境下でも / で区切られる >>> p.as_posix() 'aaa/bbb/ccc.txt'
as_posix()
は / で区切られた文字列が返されるため、windows環境では使用できない。
じゃあwindows用のメソッドがあるかと思いきや用意されていないっぽいので、環境に依存したくなければstr()
を使うようにすべきか。
判定系
以下のメソッドはTrueかFalseで判定を返す。
# 絶対パスかどうかを判定 >>> p.is_absolute() # 現在のパスが与えられたパターンと一致するかどうかを判定 (パターンはglob形式で指定) >>> p.match('a/*txt') # パスのファイル、またはディレクトリが存在しているかどうかを判定 >>> p.exists() # ディレクトリかどうか判定 >>> p.is_dir() # ファイルかどうか >>> p.is_file() # シンボリックリンクかどうか >>> p.is_symlink() # Pathオブジェクトが指定するファイルと引数で指定したファイルが同じファイルを参照しているかどうか # 引数にはPathオブジェクトか文字列をとる >>> p.samefile(other_path)
ファイル名変更など
# 指定したファイルまたはディレクトリをtgtにリネームする >>> p.rename(tgt) # パスの末尾のファイルまたはディレクトリ名をtgtに置き換える # 存在する場合はリネームする >>> p.replace(tgt)
os.pathは潔く捨てる
ちょっとした作業用スクリプトを作るときにも便利なので、
pythonを使っているならぜひとも享受していきたいメリットである。
参考
Pythonでフォルダ内のファイルリストを取得する
Pythonでのファイル操作をosとpathlibで比較
Python3.4以降ならos.pathはさっさと捨ててpathlibを使うべき
Python、pathlibモジュールを使う - naritoブログ