【Python】相対パスをわかりやすく解説!初心者が知るべき基礎と活用例
はじめに
Pythonでファイルやディレクトリを操作するとき、相対パスを正しく扱うことはとても大切です。
たとえば、設定ファイルを読み込むときや特定のフォルダにファイルを保存するときなど、相対パスを使いこなせばコードの移植性が高まります。
相対パスの概念を理解していないと、ファイルが見つからないエラーが起きたり、環境が変わった際にコードが動作しなくなったりすることがあります。
この記事では、初心者の方がつまずきやすいポイントを解消できるよう、相対パスに関する基礎から実際の使い方、そして実務でも役立つヒントを具体的に紹介していきます。
この記事を読むとわかること
- 相対パスと絶対パスの違い
- 相対パスの基本的な書き方と特別な記号の意味
- Pythonにおける実用的な相対パスの扱い方
- 実務で役立つ相対パスの応用例と注意点
ここで紹介する内容を押さえておくと、ファイルパスを指定する場面で迷いにくくなります。
Pythonにおけるパス概念とは
Pythonを使ってファイルを操作するとき、最初に理解しておきたいのがパスという概念です。
パスは、ファイルやディレクトリが置かれている場所を示す文字列のことです。
コンピュータの中でファイルを探すとき、人間が住所を使って建物を特定するのと同じで、パスを使って「このファイルはどこにあります」と教える役割を持っています。
Pythonのコードでパスを指定する方法には、大きく分けて絶対パスと相対パスの2種類があります。
相対パスは、現在の作業ディレクトリ(カレントディレクトリ)などを基準にしてファイルの位置を表すのが特徴です。
一方、絶対パスはシステムのルートディレクトリからの完全な場所を示します。
この2種類のパスの違いを意識すると、Pythonコードを書くときに混乱しづらくなります。
ファイル操作の場面では、ちょっとした表記の違いでエラーが出ることもありますので、まずは基本の考え方をしっかり押さえておくと良いでしょう。
絶対パスと相対パスの違い
絶対パスと相対パスの違いを一言で言うなら、基準となる場所がどこかという点です。
絶対パスは、Windowsなら「C:\Users\Username\Desktop\example.txt」のようにルートドライブから書き始めます。
MacやLinuxであれば「/Users/username/Desktop/example.txt」のように、スラッシュ(/)を先頭につけてルートディレクトリを基準に指定します。
対して相対パスは、現在いるディレクトリを基準にしてファイルの所在を示します。
たとえば、カレントディレクトリが「/Users/username/Desktop/」であれば、同じデスクトップにあるexample.txtは「example.txt」と書くだけでアクセスできます。
別のフォルダにあるファイルであれば「../」や「./」といった特別な記号を使って、一つ上の階層や同じ階層を指定できます。
具体的には「./config/settings.ini」のような書き方をするわけです。
絶対パスはいつでも確実にファイルの場所を特定できるのでわかりやすい反面、ファイル構成を変更すると書き換えが面倒な場合があります。
一方、相対パスはプロジェクト内でファイルの位置が変わらなければ、どのディレクトリにプロジェクトを置いても同じ書き方でアクセスできます。
この柔軟性が相対パスの利点ですが、あくまでも基準となるディレクトリがどこかを知っていないといけない点に注意が必要です。
相対パスが必要となるケース
相対パスはプロジェクト開発においてよく使われます。
特に次のような場面では、相対パスの活用が欠かせません。
プロジェクトの共有
チーム開発などで同じフォルダ構成を別の環境に複製するとき、相対パスなら変更せずに動くことが多いです。
複数マシン間でのコード移動
ノートパソコンとデスクトップなど、ファイルパスのルートが違うPC間でコードをやりとりするときに便利です。
継続的なフォルダ変更の可能性がある場合
後でディレクトリの構造を変更しそうな場合は、相対パスにしておけばコード側の修正範囲を減らせることがあります。
たとえば、プログラムが設定ファイルを読み込むとき、相対パスで記述しておけばプロジェクトのルート直下にあるファイルを「config.yaml」などと書くだけで済みます。
別のフォルダに移動しても、上位階層や同階層からの相対距離が変わらなければ修正は最小限です。
一方で、動作環境によってカレントディレクトリが変わってしまう場合もあるので、その点は後述する注意点を参考にしてください。
相対パスでよく利用される特別な記号
相対パスの指定で覚えておくと役立つのが、**.
(ドット)と..
(ドットドット)**の2つの記号です。
.
は、現在のディレクトリを示します。
たとえば「./data」というパスは、「今いるディレクトリの中にあるdataというフォルダ」を意味します。
一方、..
は1つ上のディレクトリを示します。
たとえば「../images」というパスであれば、「今いるディレクトリの一つ上の階層にあるimagesというフォルダ」を意味します。
Pythonのコードを書くときも、これらの記号を使って相対パスを指定します。
ちょっとしたファイルアクセスなら.
や..
を使うだけで十分ですが、階層が深くなるとどこまで「../」を繰り返すのか混乱するケースがあります。
この点は後ほど紹介するos
モジュールやpathlib
モジュールを使うことで、よりシンプルにコードを書けるようになります。
osモジュールで相対パスを扱う方法
Pythonで相対パスを扱う場合、まず頭に浮かびやすいのがosモジュールです。
古くから使われてきたモジュールであり、os.path
という仕組みを利用してパスの結合や変換などを行うことができます。
たとえば、以下のようなコードで相対パスを使ってファイルのパスを組み立てられます。
import os # カレントディレクトリのパスを取得 current_dir = os.getcwd() # 相対パスを結合して新しいパスを作る relative_path = os.path.join(current_dir, "data", "sample.txt") # 作成したパスを使ってファイル操作をするイメージ print("相対パスで結合したパス:", relative_path)
このサンプルでは、まずos.getcwd()
で現在のディレクトリを取得し、それに対して「data」「sample.txt」という相対的なパス要素を結合しています。
プロジェクトのフォルダ構成がある程度決まっていれば、os.path.join()
を使いながら相対パスを組み立てていくとわかりやすいです。
なお、Pythonを実行する際にどのフォルダをカレントディレクトリとしているかによって、同じ相対パス表記でも異なる場所を指す可能性があります。
この点を見落とすと「ファイルが見つからない」というエラーが起きることがありますので、実行環境を確認する習慣をつけておくと良いでしょう。
pathlibモジュールで相対パスを扱う方法
近年では、pathlibモジュールを使う方法が広く取り入れられています。
pathlib
はオブジェクト指向のアプローチを採用しており、パスを文字列ではなくPath
オブジェクトとして扱うことが特徴です。
こちらも相対パスを組み立てる際に便利なので、ぜひ押さえておきたいところです。
from pathlib import Path # カレントディレクトリを取得 current_dir = Path.cwd() # 相対パスでファイルパスを結合 file_path = current_dir / "data" / "sample.txt" print("pathlibで組み立てたパス:", file_path)
Path.cwd()
で現在のディレクトリを示すPath
オブジェクトを取得し、その後はスラッシュ(/)演算子でディレクトリ名やファイル名を結合しています。
文字列の連結よりも読みやすく、シンプルに書けるのが特長です。
相対パスで操作したい場合は、Path("data/sample.txt")
のように直接表記しても問題ありません。
この場合、カレントディレクトリを基準とした相対パスになります。
また、resolve()
メソッドを呼べば、その相対パスが実際にはどの絶対パスに対応するかを確認できるので、トラブルシューティングにも役立ちます。
エラーとトラブルシューティング
相対パスを使うときによくあるエラーは「ファイルが見つからない」というものです。
一見正しく書けているように思えても、実行時にカレントディレクトリが予想と違う場所になっていたり、相対パスの階層指定を誤っていたりするとファイルを読み込めません。
WindowsやMac(Linux)など異なるOSで実行するときも、パスの区切り文字が異なる点に注意が必要です。
ただし、os.path.join()
やpathlib
を使うと、OSに合わせたパスが自動的に生成されるので、基本的には大きな問題を避けられます。
もしファイルアクセスに失敗した場合は、次のような手順で原因を探ると良いでしょう。
- カレントディレクトリの確認
- 実際に組み立てられたパスを表示し、想定と一致しているかチェック
pathlib
ならresolve()
して絶対パスを表示する- そもそもファイルやフォルダが存在するか確認する
このように確認作業をこまめに行えば、相対パス絡みのエラーを素早く発見できます。
実務でよくある相対パスの使い所
実務で相対パスがよく使われる典型的なシーンとしては、複数のPythonスクリプトで設定ファイルやテキストデータを共有している場合があげられます。
たとえば、以下のようなフォルダ構成を考えてみましょう。
project/ ├── main.py ├── config/ │ └── settings.json └── data/ └── user_data.csv
main.py
から見ると、config/settings.json
やdata/user_data.csv
は同じプロジェクト直下にある別フォルダに置かれています。
このとき、相対パスを使うと次のように書けます。
from pathlib import Path project_root = Path.cwd() # カレントディレクトリが "project/" であると仮定 config_file = project_root / "config" / "settings.json" data_file = project_root / "data" / "user_data.csv" print(config_file) print(data_file)
もしチームメンバーが、このproject/
フォルダをまるごと自分のPCにコピーして作業しても、相対パスで書かれたコードはフォルダ構成さえ変わらなければ動作します。
これが絶対パスだと、個人のPC環境に依存した記述になり、メンテナンスが大変になりがちです。
複雑なディレクトリ構成での活用例
さらにディレクトリ階層が深くなったり、サブフォルダから別のサブフォルダにあるスクリプトを呼び出したりするケースもあります。
具体的には、次のような構成が挙げられます。
project/ ├── src/ │ ├── __init__.py │ └── app.py ├── config/ │ └── default.yaml └── utils/ └── helper.py
ここでapp.py
の中から、config/default.yaml
にアクセスしつつ、utils/helper.py
で定義した関数を呼び出したい場合を考えます。
app.py
のあるディレクトリはproject/src
ですから、カレントディレクトリをどこに設定しているかで相対パスの指定が変わります。
もしカレントディレクトリがproject
だとしたら、app.py
側から見た相対パスはsrc/app.py
となります。
実務では、この点を見落としてトラブルが起きることがあるため、プロジェクトのルートディレクトリを基準にした相対パスの使い方を統一しておくと開発チーム全体が混乱しにくいです。
pathlib
で書く場合も、Path.cwd()
がどのディレクトリを指すかを事前に把握し、チーム内のコード規約などで約束事を決めておくのが無難です。
WindowsとMac(Linux)での注意点
Python自体はクロスプラットフォーム対応ですので、WindowsとMac(Linux)間の移植性が高いといわれます。
ただし、パス指定に関しては、Windowsが\
(バックスラッシュ)、MacやLinuxが/
(スラッシュ)を使うという違いがあるため、文字列ベースで扱うと混乱することがあります。
この問題を回避するためには、前述のとおりos.path.join()
やpathlib
を使うのがおすすめです。
Pythonが自動的にOSごとの適切なパス区切り文字を挿入してくれるので、あえて手動で書き換える必要はありません。
また、一部のUnicode文字やファイル名にスペースが含まれる場合は、OS側で扱い方が微妙に異なることがあります。
しかし、多くの場合はPython側が吸収してくれるため、相対パスを使っているかぎりそこまで大きな問題にはなりにくいでしょう。
import文でも相対パスは使えるのか?
Pythonでモジュールを読み込むとき、import
文を使います。
モジュールの相対インポートは、同じパッケージ内にあるモジュール同士の呼び出しで使われることがあります。
しかし、一般的なファイル操作の相対パスとは少し仕組みが異なり、 「. (ドット) 」や「..」を使う書き方をするという点が特徴です。
たとえば、パッケージ構成が以下のようになっている場合、
package/ ├── __init__.py ├── module_a.py └── module_b.py
module_b.py
の中からmodule_a
を相対インポートするには次のように書きます。
from . import module_a
これは、「同じパッケージ内からmodule_aを読み込みます」という意味になります。
ただし、相対インポートは使いこなすのがやや難しく、かえって混乱の原因になることも多いです。
チーム開発では、わかりやすさを優先して絶対インポートに統一することもあります。
ファイル操作の相対パスとは少し異なる話題ですが、Pythonのコード全体で「相対」の扱い方を考える際、こうしたインポートの違いも把握しておくと混乱を減らせます。
プロジェクト構成のコツ
相対パスを活用するためには、プロジェクトのディレクトリ構成そのものにも配慮が必要です。
たとえば、大規模なプロジェクトでフォルダを複雑に分けすぎると、相対パスを書き下すのが面倒になります。
また、チームメンバーが増えると、人によって異なる階層から相対パスを指定してしまい、後から見たときに管理が難しくなるかもしれません。
そのため、多くのプロジェクトでは以下のようなルールを定めることがあります。
- プロジェクトのルートディレクトリを基準に、全員が相対パスを書けるようにする
- 同じ階層にあるソースコードや設定ファイルは、意識的に1つのフォルダにまとめる
- 重要ファイルの場所はドキュメント化しておく
これらを徹底しておくと、相対パスで指定したファイルを探すときにも迷いにくくなり、チームメンバー全員が同じ認識を持ちやすくなります。
セキュリティリスクはあるのか?
相対パスの取り扱いでは、特定のディレクトリへのアクセスが予期せず許可されてしまうリスクが考えられます。
たとえば、外部から指定されたパスをそのまま相対パスとして処理してしまい、../
などで上位ディレクトリをさかのぼられてしまうケースです。
これをディレクトリトラバーサルと呼び、不用意に扱うと機密ファイルにアクセスされる恐れがあります。
内部的なスクリプトで完結しているなら問題ないことが多いですが、もし外部の入力をもとにファイルの読み書きを行うコードを書く場合は、入力のバリデーションをしっかり行う必要があります。
また、相対パスだけが危険というわけではなく、絶対パスでも同様のリスクが生じることはあります。
ただし、相対パスのほうが..
などで階層を移動しやすいため、注意が必要です。
相対パスでファイルを扱うとき、外部からの入力をそのまま使うのは慎重に検討しましょう。
ディレクトリトラバーサルなどのセキュリティリスクが潜んでいる場合があります。
まとめ
相対パスを正しく扱うために必要なポイントを、以下の内容で整理してきました。
相対パスは絶対パスに比べて柔軟性が高く、プロジェクト構成や環境移行の際に大きな力を発揮してくれます。
一方で、カレントディレクトリがどこかを意識する必要があり、実行環境が変わったときには動かなくなる恐れがある点に気をつけてください。
また、セキュリティリスクも念頭に置き、外部からの入力を無防備に相対パスとして処理しないようにすることが重要です。
**Pythonで相対パスを扱うための主要な方法は、os.path
とpathlib
**です。
どちらを選んでも問題ありませんが、コードの可読性や保守のしやすさを考えると、オブジェクト指向的にパスを扱えるpathlib
を積極的に使うケースが増えています。
最終的には、チーム規約やプロジェクト構成に合わせて使い分けると良いでしょう。
実務では、開発者同士で「どのディレクトリを基準に相対パスを書くか」を共有するなど、ルール作りが大事になります。
ぜひここまでの内容を参考にしながら、Pythonでの相対パスの扱い方をマスターしてみてください。