- Pathライブラリの使い方が知りたい!
このような方に向けて書きました。
Python でパス操作するときは os ライブラリを使う方が多いかもしれません。
ところが Python 3.4 から標準ライブラリとして搭載されてからは、Pathlibライブラリが使われることも徐々に増えてきました。
例えば Python の Web フレームワーク Django でも、バージョン2.0からは os の代わりに pathlib が使われています。
pathlibはosを完全に置き換えるものではありませんが、よりシンプルにパスを表現できるので圧倒的に便利です。
この Path ライブラリは、次の操作が可能です。
- ファイルの作成
- ファイルの削除
- パスの結合
- ファイルの移動など
本記事では代表的な操作を網羅したので、大体の実装の悩みにお答えできると思います。
記事が長くなってしまったので、以下の目次のリンクより該当箇所に飛んでください。
osライブラリとpathlibライブラリを比較してみる
パス操作ライブラリはosが有名ですが、pathlibを使う方が圧倒的に便利です。
pathlibの方が優れている点は次のとおりです。
- シンプルに書ける
- OSの違いを気にしないで書ける
- メソッドが多く可読性が上がる
それぞれ解説します。
シンプルに書ける
pathlib ではパスをオブジェクトとして扱うことができるので、osよりもシンプルに書けます。
例えば、あるパスの一つ上の階層のパスを取得する場合。
# osの場合
parent_dir = os.path.abspath(os.path.join("some/directory", os.pardir))
# pathlibの場合
parent_dir = Path("some/directory").parentカレントディレクトリ配下の全ファイルを取得する場合。
# osの場合
files = []
for root, dirs, files_in_dir in os.walk("."):
for file in files_in_dir:
files.append(os.path.join(root, file))
# pathlibの場合
files = list(Path(".").rglob("*"))どちらもシンプルで可読性が上がります。
OSの違いを気にしないで書ける
OSごとにパスの扱いは異なります。
# Windowsのファイルパス例
"C:\\Users\\YourName\\Documents\\file.txt"
# Unix系(Linux, macOS)のファイルパス例
"/home/yourname/documents/file.txt"pathlib ではパスをオブジェクト化してくれるので、これらの違いを考える必要がなくなります。
つまり、それぞれパスオブジェクトに格納してしまえば自由にpathlibのメソッドが適用可能です。
# Windowsのファイルパス例
windows_path = Path("C:\\Users\\YourName\\Documents\\file.txt")
print(windows_path.parent) # C:\Users\YourName\Documents
# Unix系(Linux, macOS)のファイルパス例
unix_path = Path("/home/yourname/documents/file.txt")
print(unix_path.parent) # /home/yourname/documentsメソッドが多く可読性が上がる
osライブラリに比べてメソッドが多いので、短いコードでさまざまなことができます。
from pathlib import Path
# カレントディレクトリから 'example_dir' ディレクトリを作成し、'example_file.txt' ファイルのパスを生成する例
# pathlib を使用
path = Path.cwd() / 'example_dir' / 'example_file.txt'
path.parent.mkdir(parents=True, exist_ok=True) # example_dir ディレクトリを作成
path.touch() # example_file.txt ファイルを作成
print(f"Path created: {path}")上記のコードをosで書くと以下になります。
import os
# カレントディレクトリから 'example_dir' ディレクトリを作成し、'example_file.txt' ファイルのパスを生成する例
# os を使用
path = os.path.join(os.getcwd(), 'example_dir', 'example_file.txt')
os.makedirs(os.path.dirname(path), exist_ok=True) # example_dir ディレクトリを作成
with open(path, 'w'): # example_file.txt ファイルを作成
pass
print(f"Path created: {path}")比較すると、pathlibの方が可読性が高いことを感じていただけると思います。
基本操作
pathlibの基本的な操作から説明します。
全ての操作の基本になりますので、特にパスオブジェクトの生成はマスターしてください。
パスオブジェクトを生成
ファイルやディレクトリを扱うためのPathオブジェクトを生成します。
from pathlib import Path
# ファイルパスを表すPathオブジェクトを作成
path = Path("/path/to/file.txt")パスを文字列ではなく、Pythonオブジェクトとして扱うための重要なステップです。
なお、PathオブジェクトはOSに関わらず取得可能です。
以下はWindowsの場合です。
from pathlib import Path
# Windowsパスの例
windows_path = Path("C:/Users/Username/Documents")
print(windows_path.exists()) # パスの存在確認Linuxでも問題なくパスオブジェクトを取得できます。
from pathlib import Path
# Linuxパスの例
linux_path = Path("/home/user/projects")
print(linux_path.exists()) # パスが存在するか確認このようにOSごとにパスの違いを意識することなく実装できるのは、とても便利です。
複数のパスを連結
パスの結合方法は、いくつかのバリエーションが用意されています。
from pathlib import Path
# joinpathメソッドを使う方法
path = Path("/path/to").joinpath("the", "file.txt")
print(path) # /path/to/the/file.txt
# '/'演算子を使う方法
path = Path("/path/to") / "the" / "file.txt"
print(path) # /path/to/the/file.txt
# 複数引数で結合
path = Path("/path/to", "the", "file.txt")
print(path) # /path/to/the/file.txtosライブラリではos.path.joinしかできなかったので、これだけの種類があるとかえって戸惑うかもしれません。
プログラミング全般に言えることですが、コード全体を通して一貫性を持たせることが大事です。
なので、可読性を上げるために結合にあたって使うコードを決めておくと良いです。
絶対パスを取得する
絶対パスはresolveメソッドだけで実装できます。
from pathlib import Path
path = Path("example.txt")
absolute_path = path.resolve()
print(absolute_path)相対パスを取得
一方の相対パスは、relative_toメソッドを使います。
from pathlib import Path
# 相対パスを取得
path = Path("/path/to/file.txt")
relative_path = path.relative_to("/path")
print(relative_path) # to/file.txtrelative_toの引数には、どのパスを基準に相対パスを取得するか(つまり、基準となるパス)を渡します。
パスの存在確認
存在確認にはexistsメソッドを使います。
from pathlib import Path
# ファイルやディレクトリの存在確認
path = Path("/path/to/file.txt")
if path.exists():
print("存在します")パスオブジェクトをPOSIXスタイルに変換
バックスラッシュが使われている Windows パスをスラッシュ区切りにする際に使います。
from pathlib import Path
windows_path = Path("C:\\Program Files\\Example")
print(windows_path.as_posix()) # "C:/Program Files/Example"ディレクトリ操作
Pathオブジェクトを使ったディレクトリ操作方法をご紹介します。
ディレクトリを作成
ディレクトリの作成は、mkdirメソッドを使います。
from pathlib import Path
# ディレクトリを作成
path = Path("/path/to/new_directory")
path.mkdir()親ディレクトリもまとめて作りたい場合にはparents=Trueを、ディレクトリがない場合だけ作りたい場合にはexist_ok=Trueを引数に渡します。
from pathlib import Path
# ディレクトリを作成
path = Path("/path/to/new_directory")
path.mkdir(parents=True, exist_ok=True)ディレクトリの削除
ディレクトリの削除にはrmdirメソッドを使います。
from pathlib import Path
# 空のディレクトリを削除
path = Path("/path/to/directory")
path.rmdir()ディレクトリか判定
対象のPathオブジェクトにis_dirメソッドを使うと、ディレクトリかどうかの判定ができます。
from pathlib import Path
# ディレクトリかどうかを判定
path = Path('new_directory')
print(path.is_dir())ディレクトリが空かどうか確認
ディレクトリが空かどうかを判定する直接のメソッドはないので、次のようにnot anyを使って実装します。
from pathlib import Path
# ディレクトリが空かどうか確認
path = Path('new_directory')
is_empty = not any(path.iterdir())
print(is_empty)iterdirは、対象のディレクトリにあるファイルやフォルダのイテレータを取得するメソッドです。
もしディレクトリが空の場合、iterdirの結果は空のイテレータになります。このため、any(path.iterdir())の結果はFalseになります。
今回は「空かどうか」を判定したいため、notをつけてis_emptyとしました。これにより、is_emptyがTrueであればディレクトリは空であることが分かります。
ディレクトリ一覧を取得
ディレクトリ一覧を取得するには、iterdirメソッドとis_dirメソッドを併用します。
from pathlib import Path
# ディレクトリ一覧を取得
directories = [d for d in Path('.').iterdir() if d.is_dir()]
print(directories)iterdirメソッドは配下のファイルとフォルダを取得するので、条件としてis_dirメソッドでディレクトリに絞り込んでいます。
仮に再帰性を持たせるとしたら、以下のようにrglobを使います。
from pathlib import Path
# 再帰的に全てのディレクトリを取得
directories = [d for d in Path('.').rglob('*') if d.is_dir()]
print(directories)親ディレクトリの名前を変更
from pathlib import Path
path = Path("/home/old_folder/file.txt")
new_path = path.with_name("new_folder") / path.name
print(new_path) # /home/new_folder/file.txtファイル操作
新しいファイルを作成
ファイルの作成には、touchメソッドが用意されています。
from pathlib import Path
# 新しいファイルを作成
path = Path("/path/to/new_file.txt")
path.touch()
karoLinuxのtouchコマンドに似ていて覚えやすい
ファイルの削除
ファイルの削除はunlinkメソッドを使います。missing_ok=Trueとすると、ファイルがない場合でもエラーを出しません。
from pathlib import Path
# ファイルを削除
path = Path("/path/to/file.txt")
path.unlink(missing_ok=True)ファイル名の変更
ファイル名の変更はrenameメソッドを使います。
from pathlib import Path
# ファイル名を変更
old_path = Path("/path/to/old_file.txt")
new_path = Path("/path/to/new_file.txt")
old_path.rename(new_path)ファイルを移動
ファイル名ではなくディレクトリ名に対してremameメソッドを使うと、ファイルの移動ができます。
from pathlib import Path
# ファイルを移動
source = Path("/path/to/file.txt")
destination = Path("/new/path/to/file.txt")
source.rename(destination)ファイルをコピーする
残念ながらpathlibにはコピーするメソッドは用意されていないので、shutil.copyでコピーを行いましょう。
import shutil
from pathlib import Path
src = Path("file.txt")
dst = Path("copy_of_file.txt")
shutil.copy(src, dst)複数ファイルをコピーする場合は、次のようにループで回します。
import shutil
from pathlib import Path
files = [Path("file1.txt"), Path("file2.txt")]
for file in files:
shutil.copy(file, Path("destination_directory") / file.name)ファイルかどうかを判定
ファイルかどうかを判定するにはis_fileメソッドを使います。
from pathlib import Path
# パスを指定
path = Path("example.txt")
# ファイルかどうかを判定
if path.is_file():
print(f"{path} はファイルです。")
else:
print(f"{path} はファイルではありません。")拡張子を変更
with_suffixメソッドを使えば拡張子の変更もラクラクです。
from pathlib import Path
path = Path("/home/user/documents/file.txt")
new_path = path.with_suffix(".md")
print(new_path) # /home/user/documents/file.md検索
ファイル名を検索
globメソッドを実行することで、ファイル名の検索ができます。
特定の拡張子を持つファイルを取得する場合は、ワイルドカードに続けて拡張子名を指定します。
from pathlib import Path
# 特定の拡張子(例:.txt)のファイルをリストアップ
txt_files = list(Path('.').glob('*.txt'))
print(txt_files)複数の拡張子に対して検索をかけたい場合は、次のようにそれぞれの結果を取得して統合します。
from pathlib import Path
import itertools
# 複数の拡張子に一致するファイルを取得
txt_files = Path(".").glob("*.txt")
md_files = Path(".").glob("*.md")
all_files = itertools.chain(txt_files, md_files)
for file in all_files:
print(file)ディレクトリ内を再帰的に探索
再帰的にディレクトリを探索するときはglob('**/*') を使います。
from pathlib import Path
# 再帰的にディレクトリ内を探索
path = Path('.')
for file_path in path.glob('**/*'):
print(file_path)ファイル一覧を取得
ファイルの一覧を取得する場合は、iterdirメソッドとis_fileメソッドを組み合わせます。
from pathlib import Path
# 現在のディレクトリ内のファイル一覧を取得
files = [f for f in Path('.').iterdir() if f.is_file()]
print(files)ディレクトリを移動
ディレクトリの移動はpathlibにないので、osライブラリと併用します。
from pathlib import Path
# 現在のディレクトリを変更
import os
os.chdir(Path('new_directory'))ファイル名やディレクトリ名を取得
ベースネーム(ファイル名.拡張子)部分だけを取得する方法です。
from pathlib import Path
# ディレクトリ名を取得
path = Path('new_directory')
print(path.name)from pathlib import Path
path = Path("/home/user/documents/file.txt")
print(path.name) # file.txtディレクトリ部分だけを取得
parentとすることで、ベースネームを除いたディレクトリ部分を取得できます。
from pathlib import Path
path = Path("/home/user/documents/file.txt")
print(path.parent) # /home/user/documentsちなみに二つ上の階層は.parent.parent、三つ上の階層は.parent.parent.parentで取れます。
拡張子だけを取得
拡張子だけをとるならsuffixメソッドを使います。
from pathlib import Path
path = Path("/home/user/documents/file.txt")
print(path.suffix) # .txtglobを使った方法
glob メソッドを使うと、ワイルドカード(* や ?)でパターンに一致するファイルやディレクトリを再帰的に取得できます。
検索・操作するために必須の知識なので、ぜひマスターしていきましょう。
カレントディレクトリの全てのファイルを取得
全ファイルを取得する場合には、globメソッドの引数に*を指定します。
from pathlib import Path
# カレントディレクトリ内のすべてのファイルを取得
files = Path(".").glob("*")
for file in files:
print(file)このコードに再帰性はないので、カレントディレクトリ直下のファイルのみ収集することになります。
パターンに一致するファイルやディレクトリを取得
globメソッドの引数にパターンを指定することで、条件にマッチしたファイルを取得できます。
例えば、以下は.txtという拡張子を持つファイルだけを取得したい場合です。
from pathlib import Path
# カレントディレクトリ内のすべてのテキストファイルを取得
files = Path(".").glob("*.txt")
for file in files:
print(file)並び替えのメソッドはないので、sortedメソッドで行います。
from pathlib import Path
# ファイルをソートして表示
files = sorted(Path(".").glob("*.txt"))
for file in files:
print(file)正規表現を使う
Pathオブジェクトに正規表現検索する直接のメソッドはないので、reライブラリと併用して検索を行います。
import re
from pathlib import Path
# 正規表現でファイル名をフィルタ
pattern = re.compile(r"file_\d+.txt")
files = Path(".").glob("*.txt")
for file in files:
if pattern.match(file.name):
print(file)大文字・小文字を無視する
lower関数とendswithメソッドを使うことで.txtや.TXTなど大文字・小文字を区別せずに全て取得できます。
from pathlib import Path
# 大文字小文字を無視してフィルタリング
files = Path(".").glob("*")
for file in files:
if file.name.lower().endswith(".txt"):
print(file)その他の特殊な操作
ここまで紹介してきた操作以外の、ちょっと特殊な操作方法をご紹介します。
「こんなこともできるのか!」といった感じでお楽しみいただければと思います。
Windowsのショートカットを扱う
pathlibにはWindowsのショートカットを直接扱う機能がないので、win32comを使って実現します。
import win32com.client
# ショートカットから実際のパスを取得する
shell = win32com.client.Dispatch("WScript.Shell")
shortcut = shell.CreateShortCut("C:/path/to/shortcut.lnk")
print(shortcut.Targetpath)ちなみにwin32comを使うとExcelやOutlookなどの操作もできるので、興味のある方は試してみてください。
詳しくは以下の記事で解説しました。




ディレクトリをコピーする
ディレクトリのコピーはpathlibに含まれないので、shutilライブラリで実装します。
import shutil
from pathlib import Path
src = Path("source_directory")
dst = Path("destination_directory")
shutil.copytree(src, dst)パス操作を模擬する
Path.exists メソッドをモックして、テスト時に常に指定したパスが存在するように見せかける方法です。
unittest.mock.patchを使います。
from unittest.mock import patch
from pathlib import Path
# パスの存在確認をモック
with patch('pathlib.Path.exists', return_value=True):
path = Path("/mock/path")
print(path.exists()) # Trueこれにより、実際にはパスの存在確認をせずに常にTrueを返すことができます。











コメント