こんにちは、Zero-Cheeseです。
本記事では、
- pathlibモジュールの特徴と
- よく使うPythonコード
をご紹介しています。
- Python初心者(最低限の文法をご存知の方)
- pathlibに初めて触れる方
を対象とした内容となっています。
pathlibの特徴を紹介した後に、頻繁に使用される「Pythonコード」を、ご紹介しました。
pathlibの特徴
既にご存知の方は、「Pythonコードの紹介」の章まで、Skipして下さい。
pathlibとは?
pathlibは、「ファイルパス、ディレクトリパス」の操作を行うパッケージで、Python3.4から追加されました。
ファイルパス、ディレクトリパス操作を、オブジェクトから操作します。
例えば、「./sample.txt」ファイルを削除する場合、
- osパッケージと、
- pathlibパッケージの
コードの違いは、下記の通りです。
# osを使用する場合
os.remove("./sample.txt")
# pathlibを使用する場合
p = pathlib.Path("./sample.txt").unlink()
p.unlink()
# もちろん1行で書いてもOK ⇨ pathlib.Path("./sample.txt").unlink()
pathlibは、オブジェクトを使って、処理しています。
「pathlib」使って、何か嬉しい?
「pathlib」で処理できる事は、「os」等を使った処理と同じです。
それでも、「pathlib」を使う事のメリットを、ご紹介します。
- パス関係の処理が、1つのパッケージにまとまっている。
- パス関係処理が、連続して記述できる
以下、順番に紹介していきます。
パス関係の処理が1つのオブジェクトにまとまっている。
パス関係の処理というのは、
- ファイル名を変更したり
- 該当するファイルパスを取得したり
する操作を指します。
これらの操作は、「os」、「os.path」、「glob」等、複数のパッケージに散らばっていましたが、「pathlib」パッケージ1つで、ほぼ網羅できます。
また昨今は、オブジェクト指向が当たり前になっているので、パス関連操作が「オブジェクト」から扱える事も、大きなメリットです。
パス関係の処理が、連続して記述できる
例えば、
- パスを絶対パスに変換して、
- その絶対パスに、ファイルパスを追加して、
- そのファイルが存在するか確認する
という操作を考えてみます。
「pathlib」を使用しないコードと、使用したコードを比較してみます。
# 「pathlib」を使用しないコード
file_path = os.path.abspath('./AAA')
file_path = os.path.join(file_path, 'sample.txt')
print(os.path.exists(file_path))
# 「pathlib」を使用したコード
print(pathlib.Path('./AAA').resolve().joinpath('sample.txt').exists())
上記コードの通り、Javascriptのチェーンメソッド等みたいに、連続して記述する事が可能です。
よく使われるPythonコードをご紹介
「pathlib」は、標準モジュールに含まれているため、追加インストール不要です。(Python3.4以上のみ)
「pathlib」パッケージの読込み
import pathlib
まずは、「Path」オブジェクトの作る
pathlib.Path({パスを指定})
引数に関して:
- 「絶対パス」、「相対パス」どちらも可(省略時、カレントディレクトリ)
- パスの最後に、/ を付けても付けなくてもOK(pathlib.Path(‘./sample_dir‘) 、pathlib.Path(‘./sample_dir/‘) 両方OK)
コード例:
p = pathlib.Path('./sample.txt')
# print(type(p)) を実行すると
# PosixPath('./sample.txt') が表示される(Macの場合)
pathlib.Pathが返す型(上記コードの、変数 p の型 )
- UNIX系(Mac等):PosixPath
- Windows:WindowsPath
(これらは、Pathクラスを継承したクラスのため、本記事では、Pathオブジェクトと表現している箇所があります。)
「ホームディレクトリ」や、「カレントディレクトリ」を指定したい場合、下記方法が使えます。
# 「ホームディレクトリ」を指定したい場合
p = pathlib.Path.home()
# 「カレントディレクトリ」を指定したい場合
p = pathlib.Path.cwd()
「パス」に関連した、確認系の処理
ディレクトリ・ファイルの存在確認
引数に指定した「パス」が、実際に存在するかどうか、確認できます。
(Pathオブジェクト).exists()
- 存在する場合:True
- 存在しない場合:False
が返ります。
コード例:
p = pathlib.Path('./sample.txt')
is_exsits = p.exists()
# 結果: True or False
指定したパスが、ファイル、ディレクトリ、絶対パスなのかを判定
Pathオブジェクトの、引数に指定した「パス」が、
- ファイルなのか
- ディレクトリなのか
- 絶対パスなのかを
確認する事ができます。
- ファイル判定メソッド: (Pathオブジェクト).is_file()
- ディレクトリ判定メソッド: (Pathオブジェクト).is_dir()
- 絶対パス判定メソッド: (Pathオブジェクト).is_absolute()
- 該当する場合:True
- 該当しない場合:False
が返ります。
指定したパスに、ファイル/ディレクトリが実際に存在しない場合は、Falseが返ります。
コード例:
# ファイル判定
p = pathlib.Path('./sample.txt')
is_file = p.is_file()
# ディレクトリ判定
p = pathlib.Path('./sample_dir')
is_dir = p.is_dir()
# 絶対パス判定
p = pathlib.Path('./sample_dir')
is_absolute = p.is_absolute()
配下のディレクトリ/ファイルを取得
全て(ディレクトリ/ファイル 両方含む)、取得する
「Path」オブジェクトのパス配下にある、ディレクトリ/ファイル一覧を取得するメソッドです。
(Pathオブジェクト).iterdir()
ジェネレータが返ります。
コード例:
p = pathlib.Path('sample_dir')
p_iter = p.iterdir()
# list(p_iter)の実行例:
# [PosixPath('sample_dir/sub_dir'),
# PosixPath('sample_dir/3.txt'),
# PosixPath('sample_dir/2.txt'),
# PosixPath('sample_dir/1.txt')]
該当する「ファイル、ディレクトリ」のみ、取得する
(Pathオブジェクト).glob(“{検索条件}”)
引数に関して:
globパッケージのglob関数と同じ使い方です。(例えば、「*」を指定すると、0文字以上の任意の文字列に該当)
ジェネレータが返ります。
コード例:
p = pathlib.Path('./')
p_glob = p.glob("*.txt")
# print(list(p_glob)) を実行した結果(例)
# [PosixPath('sample1.txt'), PosixPath('sample2.txt')]
親ディレクトリの取得
親ディレクトリ一覧を取得する
- 親ディレクトリ一覧: (Pathオブジェクト).iterdir()
ジェネレータが返ります。(最初に「親のPathオブジェクト」が、次に「親の親」が返ります。)
コード例:
# 例えば、「"/AAA/BBB/CCC"」パスで、オブジェクトを作った場合
p = pathlib.Path('/AAA/BBB/CCC')
p_parents = p.parents
# list(p_iter)の実行:
# [PosixPath('/AAA/BBB'), PosixPath('/AAA'), PosixPath('/')]
1つ上、2つ上の、親ディレクトリを取得する
- 1つ上の親を取得: (Pathオブジェクト).parents[0]
- 2つ上の親を取得: (Pathオブジェクト).parents
PosixPath(Unix系)、WindowsPath(windows)型が返ります。
コード例:
# 例えば、「"/AAA/BBB/CCC"」パスで、オブジェクトを作った場合
p = pathlib.Path('/AAA/BBB/CCC')
p_parents0 = p.parents[0]
p_parents1 = p.parents
# print(p_parents0)を実行 ⇨ "/AAA/BBB"
# print(p_parents1)を実行 ⇨ "/AAA"
pathlibの「パス」を変更する処理関係
相対パスを絶対パスに変換
- (Pathオブジェクト).resolve()
PosixPath(UNIX系)、WindowsPath(Windows)型が返ります。
コード例:
p = pathlib.Path('./sample_dir')
p = p.resolve()
# print(p)を実行 ⇨ (例) "/Users/foo/AAA/sample_dir"
パスのファイル名を変更する
(Pathオブジェクト).with_name({変更したいファイル名})
PosixPath(UNIX系)、WindowsPath(Windows)型が返ります。
コード例:
p = pathlib.Path('AAA/BBB/sample.txt')
p_name = p.with_name('change.txt')
# print(p_name)を実行 ⇨ "AAA/BBB/change.txt"
パスの拡張子のみを変更する
(Pathオブジェクト).with_name({変更したいファイル名})
PosixPath(UNIX系)、WindowsPath(Windows)型が返ります。
コード例:
p = pathlib.Path('AAA/BBB/sample.txt')
p_suffix = p.with_suffix('.png')
# print(p_name)を実行 ⇨ "AAA/BBB/sample.png"
現在のPathオブジェクトに、新たなパスを追加する
(Pathオブジェクト).joint({追加したいパス})
引数に関して:
「追加したいパス」は、可変長引数のため、任意の数の指定が可能です。
また「追加したいパス」は、文字列、Pathオブジェクト、どちらも可能です。(下記コードを参照)
PosixPath(UNIX系)、WindowsPath(Windows)型が返ります。
コード例:
# パスの結合 その1
p = pathlib.Path('AAA')
p_joint = p.joinpath('BBB', 'CCC')
# print(p_joint)を実行 ⇨ "AAA/BBB/CCC"
# パスの結合 その2
p = pathlib.Path('AAA')
p_joint = p.joinpath(pathlib.Path('BBB'), 'CCC', 'DDD')
# print(p_joint)を実行 ⇨ "AAA/BBB/CCC/DDD"
文字列として取得する方法
Pathオブジェクトの「パス」を、文字列で取得
- str(Pathオブジェクト)
- (Pathオブジェクト).as_posix()
文字列が返ります。
①はUNIX系の場合、POSIX形式(ディレクトリを「/」で区切った方式)が、Windowsの場合、Windowsに対応したパス表示が返ります。(下記コード参照)
②は、POSIX形式(ディレクトリを「/」で区切った方式)で返ります。
コード例:
p = pathlib.Path('/AAA/BBB/CCC')
print(str(p))
# 実行結果
# UNIX系の場合: /AAA/BBB/CCC
# Windowsの場合: \\AAA\\BBB\\CCC
print(p.as_posix())
# 実行結果 (UNIX系、Windows、両方同じ結果)
# /AAA/BBB/CCC
ファイル名、拡張子抜きファイル名、拡張子を取得する
- ファイル名:(Pathオブジェクト).name
- 拡張子抜きファイル名:(Pathオブジェクト).stem
- 拡張子:(Pathオブジェクト).suffix
コード例:
p = pathlib.Path('/AAA/sample.txt')
# ファイル名の取得
print(p.name)
# ⬆ 実行結果:「sample.txt」
# ファイル名(拡張子抜き)の取得
print(p.stem)
# ⬆ 実行結果:「sample」
# 拡張子の取得
print(p.suffix)
# ⬆ 実行結果:「.txt」
Pathオブジェクトの「パス」を、ディレクトリまでのパスと、ファイル名に分離して、取得する
- os.path.split(Pathオブジェクト)
コード例:
p = pathlib.Path('AAA/BBB/sample.txt')
print(os.path.split(p))
# ⬆ 実行結果
# ('AAA/BBB', 'sample.txt')
ファイル操作(作成、削除など)
空ファイルの作成
- (Pathオブジェクト).touch(mode=0o666, exist_ok=True)
引数が省略された場合、上記のデフォルト値が設定されます。
引数に関して:
- mode:ディレクトリに対する権限 (先頭の「0o」は、8進数を表しています。)
- exist_ok:「True」にすれば、既に該当ファイルがある場合でも、例外(FileExistsError)が発生しない。
コード例:
p = pathlib.Path('test.txt')
p.touch()
# 実行すると、「text.txt」ファイルが作成される。
ファイルの削除
- (Pathオブジェクト).unlink(missing_ok=False)
引数が省略された場合、上記のデフォルト値が設定されます。
引数に関して:
- missing_ok:「True」にすれば、既に該当ファイルがある場合でも、例外(FileExistsError)が発生しない。
コード例:
# 標準的な使い方
p = pathlib.Path('test.txt')
p.unlink()
# 実行すると、「text.txt」ファイルが削除
# ファイルが無くても、例外発生しない使い方
p.unlink(True) # 引数に、missing_ok=True でもOK
ファイル操作権限の変更
(Pathオブジェクト).chmod({指定したい権限})
引数には、指定したい権限を、8進数(0oから始まる3桁の数字)で指定します。
コード例:
p = pathlib.Path('sample.txt')
p.chmod(0o666)
# 上記を実行すると、権限が「-rw-rw-rw-」になる。
ファイル名を変更、移動
(Pathオブジェクト).rename({変更後のパス})
引数の使い方は、下記コードをご参照ください。
Pathオブジェクトに、指定したファイルがない場合は、例外(FileNotFoundError)が発生します。
コード例:
# ファイル名のみ、変更したい場合
p = pathlib.Path('./sample.txt')
p.rename('./aaa.txt')
# ファイルを、別ディレクトリに移動したい場合
# 下記の場合、「AAA」ディレクトリが存在しないと、エラー発生
p = pathlib.Path('./sample.txt')
p.rename('./AAA/sample.txt')
# 移動先に、同名のファイルがある場合は、上書き
# 上記2つを組み合わせるのも可能
p = pathlib.Path('./sample.txt')
p.rename('./AAA/aaa.txt')
ディレクトリ操作関係
ディレクトリ名を変更する
ファイル名の変更と、全く同じメソッドで、変更します。
(Pathオブジェクト).rename({変更後のパス})
引数の使い方は、下記コードをご参照ください。
Pathオブジェクトに指定したディレクトリがない場合は、例外(FileNotFoundError)が発生します。
コード例:
# ディレクトリ名の変更
p = pathlib.Path('./AAA') # ディレクトリへのパスを指定
p.rename('./BBB') # 変更したいディレクトリ名を指定
ディレクトリを作成
- (Pathオブジェクト).mkdir(mode=0o777, parents=False, exist_ok=False)
引数が省略された場合、上記のデフォルト値が設定されます。
引数に関して:
- mode:ディレクトリに対する権限 (先頭の「0o」は、8進数を表しています。)
- parents:中間ディレクトリも作成したい場合、引数に「parents=True」を指定
- exist_ok:「True」にすれば、既に該当ディレクトリがある場合でも、例外(FileExistsError)が発生しない。
コード例:
# 標準的な使い方
p = pathlib.Path('sample_dir')
p.mkdir()
# 実行すると、「sample_dir」ディレクトリが作られる
# 中間ディレクトリも作りたい場合
p = pathlib.Path('sample_dir/sub_dir')
p.mkdir(parents=True)
# 実行すると、「sample_dir」ディレクトリが作られた上に、
# その配下に、「sub_dir」ディレクトリも作成
ディレクトリを削除
- (Pathオブジェクト).rmdir()
ディレクトリの中身が空でない場合、例外(OSError)が発生します。
コード例:
p = pathlib.Path('sample_dir')
p.rmdir()
ディレクトリの中身+ディレクトリを全削除
「shutil」パッケージを使用します。
- shutil.rmtree(‘削除したいディレクトリパス’)
引数に、削除したいディレクトリパスを、文字列で設定します。
コード例:
import shutil
shutil.rmtree('sample_dir')
# 実行結果、ディレクトリも含めて全消去される
最後に
本記事では、「Pathlib」の特徴と使い方を、紹介しました。
ビジネスでコードを作る際は、コード品質を担保する観点からも、「pathlib」の使用が標準になってくると思います。
本記事を通して、使い方を把握して頂けたら、幸いです。
それではまた、お会いしましょう!