[Python]pathlibの使い方

Python

pathlibはインストール不要で使えるPythonの標準ライブラリです。

Pythonのバージョン3.4以上で使用できます。

このページでは、pathlibでよく使うメソッドとプロパティをまとめ、ディレクトリの中に入っているパスの取り出しや、検索を行っていきます。

公式ドキュメント pathlib[docs.python.org]

私の環境
WSL2 - Ubuntu 20.04 LTS
docker Python 3.9.0

 Androidアプリを作成しました。
 感情用のメモ帳です。

スポンサーリンク
スポンサーリンク

Pathオブジェクトの作成

まずpathlibモジュールからPathクラスをインポートします。

そしてPathクラスのオブジェクトを作成します。

from pathlib import Path

Path('ファイルやディレクトリのパス')

Pathの引数に何も渡さないと、カレントディレクトリのパスオブジェクトが作成されます。

>>> from pathlib import Path
>>> p = Path()
>>> p
PosixPath('.')

作成されたのはPathのサブクラス、PosixPathクラスのオブジェクトです。
使用しているOSによって、Unix系ならPosixPath、WindowsならWindowsPathが自動で作成されます。

引数には絶対パスか相対パスの文字列を渡します。

>>> ap = Path('/home/fuji/') # 絶対パス
>>> ap
PosixPath('/home/fuji')
>>> rp = Path('..') # 相対パス
>>> rp
PosixPath('..')

MacやLinuxでの絶対パス・相対パス↓

Windowsでのパス↓

引数に複数の文字列を渡すと、結合したパスのオブジェクトが作られます。

>>> p = Path('/home', 'user', 'test.py')
>>> p
PosixPath('/home/user/test.py') #絶対パス
>>> p = Path('user', 'bin')
>>> p
PosixPath('user/bin') #相対パス

パスオブジェクトにスラッシュ(/)を使うと、パスの追記ができます。

>>> p = Path('/home/fuji/')
>>> new = p / 'testdir'
>>> p
/home/fuji
>>> new
/home/fuji/testdir

よく使うメソッド・プロパティ

相対パスを絶対パスに

メソッドのresolveを使うと絶対パスにしたものが返ってきます。

>>> p = Path()
>>> p
PosixPath('.')
>>> p.resolve()
PosixPath('/home/fuji/code')

現在のディレクトリのパスを返す

cwdメソッドで、カレントディレクトリのパスが返ってきます。

>>> p = Path('./test.py')
>>> p.cwd()
PosixPath('/home/fuji/code')

ホームディレクトリのパスを返す

homeメソッドは、ユーザーのホームディレクトリがあればそのパスを返します。

>>> Path().home()
PosixPath('/home/fuji')

親ディレクトリのパスを取得

parentプロパティか、parentsプロパティを使うと、親ディレクトリのパスを取得できます。

parentで自身の親ディレクトリのパスを、
parentsではリストと同じようにアクセスし、親をさかのぼることができます。

parents[0]で、自身のひとつ上(つまり親)のディレクトリ、
parents[1]を入れると親の親、
parents[2]なら親の親の親というふうに、
さかのぼれる所までは取得できます。

>>> p
PosixPath('/home/fuji/code')
>>> p.parent
PosixPath('/home/fuji')
>>> p.parents[0]
PosixPath('/home/fuji')
>>> p.parents[1]
PosixPath('/home')
>>> p.parents[2]
PosixPath('/')
>>> list(p.parents)
[PosixPath('/home/fuji'), PosixPath('/home'), PosixPath('/')]

さかのぼれないところまでいくと、インデックスエラーになります。

ファイル名を取得

オブジェクトがファイルであれば、nameプロパティでファイル名を文字列として取得します。

>>> p = p / 'test.py'
>>> p
PosixPath('/home/fuji/code/test.py')
>>> p.name
'test.py'
>>> type(p.name)
<class 'str'>

拡張子を除いた名前部分を取得するには、stemプロパティ、

逆に拡張子の文字列を取得するには、suffixを使います。

>>> p.stem
'test'
>>> p.suffix
'.py'

ファイルやディレクトリが実際にあるか確認

existsメソッドは、ファイルやディレクトリの存在確認をします。

>>> Path('test.py').exists()
True
>>> Path('main.py').exists()
True
>>> Path('test.txt').exists()
False

存在するならTrue、しないならFalseが返ってきます。

ファイルかディレクトリか

ファイルか確かめるには、is_fileメソッド、

ディレクトリか確かめるには、is_dirメソッドを使います。

>>> Path('test.py').is_file()
True
>>> Path('test.py').is_dir()
False
>>> Path('test.txt').is_file() #存在しないファイル
False

そもそも存在しないものにはFalseが返ってきます。

ファイル操作

ファイルの作成

ファイルの作成は、touchメソッドで行います。

もし作成しようとしているファイルがすでに存在していた場合、上書きされます。
上書きしたくないときは、touchの引数に「exist_ok=False」を追加すると、エラーが発生して作成を止めてくれます。

>>> Path('newfile.txt').touch()
>>> Path('newfile.txt').exists()
True
>>> Path('newfile.txt').touch(exist_ok=False)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.9/pathlib.py", line 1304, in touch
    fd = self._raw_open(flags, mode)
  File "/usr/local/lib/python3.9/pathlib.py", line 1116, in _raw_open
    return self._accessor.open(self, flags, mode)
FileExistsError: [Errno 17] File exists: 'newfile.txt'

作りたいパスのオブジェクトを作成し、そのオブジェクトに対してtouchメソッドを実行しています。

ファイルを作成した後、存在確認をして「True」が返ってきているので、無事作成されていることがわかります。

ディレクトリの作成

ディレクトリの作成は、mkdirメソッドで行います。

>>> Path('newdir').mkdir()
>>> Path('newdir').exists()
True

親ディレクトリも含めて作成したいときは、引数に「parents=True」を渡します。

>>> Path('maindir/subdir').mkdir(parents=True)

「maindir」と「subdir」どちらのディレクトリも存在しません。
メソッドを実行すると両方とも作成されます。

リネーム

リネームを行うにはrenameメソッドを使います。そのままですね。

rename(変更後の名前)

引数には変更したい名前のパスオブジェクト文字列を渡します。

>>> Path('newdir').rename('renamed_dir')
PosixPath('renamed_dir')
>>> Path('newdir').exists()
False
>>> Path('renamed_dir').exists()
True

「newdir」という名前のディレクトリを「renamed_dir」に変更しました。

削除

ファイルの削除はunlink

ディレクトリの削除はrmdirを使います。
中身が空でないと削除できません。

>>> Path('test.py').unlink()
>>> Path('subdir').rmdir()

ディレクトリの中身を取り出す

パスがディレクトリであれば、メソッドのiterdirを使用し、for文にかけることで中に入っているもののパスを取り出すことができます。

>>> p = Path('/home/fuji/code')
>>> for item in p.iterdir():
...     print(item)
... 
/home/fuji/code/memo.txt
/home/fuji/code/img4532.jpeg
/home/fuji/code/maindir
/home/fuji/code/rename.py
/home/fuji/code/test.py
/home/fuji/code/img4533.jpeg

sorted関数に渡すことでソートしたリストを取得できます。

>>> sorted(p.iterdir())
[PosixPath('/home/fuji/code/img4532.jpeg'), PosixPath('/home/fuji/code/img4533.jpeg'), PosixPath('/home/fuji/code/maindir'), PosixPath('/home/fuji/code/memo.txt'), PosixPath('/home/fuji/code/rename.py'), PosixPath('/home/fuji/code/test.py')]

ディレクトリの中身を検索する

メソッドのglobで中身の検索ができ、パターンにマッチしたものを取り出すことができます。

glob(パターン)

引数には文字列を渡しますが、「*」と「?」は特別な機能を持ちます。

* はすべての文字にマッチし、
? は任意の一文字にマッチします。

>>> # for文にかける
>>> for item in p.glob('*.py'):
...     print(item)
... 
/home/fuji/code/rename.py
/home/fuji/code/test.py

>>> # リスト化
>>> list(p.glob('img453?.jpeg'))
[PosixPath('/home/fuji/code/img4532.jpeg'), PosixPath('/home/fuji/code/img4533.jpeg')]

>>> list(p.glob('test*'))
[PosixPath('/home/fuji/code/test.py')]

**/パターン」のようにすると、サブディレクトリを含めてパターンの文字列を検索します。

>>> sorted(p.glob('**/*.py'))
[PosixPath('/home/fuji/code/maindir/printer.py'), PosixPath('/home/fuji/code/rename.py'), PosixPath('/home/fuji/code/test.py')]

まとめ

このページで紹介したプロパティとメソッドです。

対象プロパティ
親ディレクトリPath.parent
Path.parents
ファイル名Path.name
Path.stem
Path.suffix
機能メソッド
絶対パスにPath.resolve()
カレントディレクトリPath.cwd()
ホームディレクトリPath.home()
存在確認Path.exists()
ファイルか
ディレクトリか
Path.is_file()
Path.is_dir()
ファイル作成
ディレクトリ作成
Path.touch()
Path.mkdir()
リネームPath.rename(変更後の名前)
ファイル削除
ディレクトリ削除
Path.unlink()
Path.rmdir()
ディレクトリの取り出しPath.iterdir()
検索Path.glob(パターン)

大量にあるファイルの削除、またコピーには、別のライブラリ「shutil」の方が適しているようです。
機会があればまとめていきたいと思います。

このページが少しでもお役に立てたのなら幸いです。

タイトルとURLをコピーしました