Pythonのimport完全ガイド!パッケージとモジュールの階層構造をスッキリ理解しよう
こんにちは。ゆうせいです。
Pythonを学び始めると、必ず出会うのが import という記述ですね。
便利なライブラリを読み込むときにも使いますし、自分で作った別のファイル(モジュール)を読み込むときにも使います。
でも、ファイルが一つや二つのうちは上手くいっていたのに、プロジェクトが大きくなってフォルダを分け始めた途端、「import が見つかりません(ModuleNotFoundError)」というエラーに出会って混乱した経験はありませんか?
「さっきまで動いていたのに、なぜ!?」
その悩み、とてもよく分かります。
その原因は、Pythonがファイルを探す「順序」と「ルール」、つまり「インポート階層」をまだ掴めていないからかもしれません。
今日は、Pythonがどのようにして import するファイルを見つけているのか、その「住所」の仕組みを、例え話を交えながら解き明かしていきましょう。
すべての基本、「モジュール」と「パッケージ」
まず、二つの大切な専門用語を押さえてしまいましょう。
専門用語解説:「モジュール(Module)」
モジュールとは、簡単に言えば「Pythonのファイル(.pyファイル)」そのもののことです。
機能ごとに処理をまとめた「道具箱」のようなイメージですね。
私たちは import 〇〇 と書くことで、その道具箱を使えるようにするわけです。
専門用語解説:「パッケージ(Package)」
パッケージとは、「モジュール(道具箱)を集めて入れたフォルダ」のことです。
ただし、ただのフォルダではありません。
Pythonに「やあ、このフォルダはただの入れ物じゃなくて、道具箱(モジュール)がたくさん入った『倉庫』だからね!」と教えてあげるための「目印」が必要になります。
その目印こそが、__init__.py(アンダースコア二つ、init、アンダースコア二つ、ドット、py)という名前の、空っぽのファイルです。
この __init__.py ファイルが置かれているフォルダだけが、Pythonの世界では「パッケージ(倉庫)」として認識されます。
Pythonはどうやってファイルを探す?「sys.path」の秘密
では、私たちが import my_tools と書いたとき、Pythonはどうやって my_tools.py という道具箱(モジュール)を探し出すのでしょうか?
実は、Pythonは「探すべき場所のリスト」をあらかじめ持っています。
そのリストのことを、専門用語で sys.path(シス・パス)と呼びます。
sys.path は、Pythonがモジュールを探しに行く「住所録」や「捜索リスト」のようなものだと考えてください。
Pythonは、このリストの上から順番に「〇〇というファイルはありますか?」と探しに行きます。
この sys.path には、主に以下の場所が登録されています。
- 今、実行しているスクリプトがあるフォルダ(カレントディレクトリ)これが一番大事です! だから、同じフォルダにあるファイル同士は、いつでも簡単に import できるんですね。
- Pythonをインストールしたときに最初から入っているライブラリの場所(標準ライブラリ)
- pipなどで後から追加したライブラリの場所(サードパーティライブラリ)
このリストの どこか に見つかれば import は成功し、リストの最後まで探しても見つからなければ「ModuleNotFoundError(モジュールが見つかりません)」となるわけです。
階層の核心!「絶対インポート」と「相対インポート」
さて、プロジェクトが大きくなり、パッケージ(倉庫)の中にさらにパッケージ(小倉庫)を作るような、複雑な階層構造になってきたとします。
my_project/
├── main.py
└── company/
├── __init__.py
├── staff.py
└── products/
├── __init__.py
└── tools.py
こんな構造を想像してみてください。
my_project がプロジェクトの入り口です。
company はパッケージ(倉庫)で、その中に staff.py(道具箱)があります。
さらに company の中には products という別のパッケージ(小倉庫)があり、その中に tools.py があります。
このとき、ファイルの指定方法(住所の書き方)には2種類あります。
1. 絶対インポート (Absolute Import)
これは、「プロジェクトの入り口(ルート)から見た、完全な住所」を指定する方法です。
上の例で、もし main.py が tools.py を読み込みたい場合、こう書きます。
# main.py の中
import company.products.tools
これは、「company という倉庫の中の、products という小倉庫の中の、tools という道具箱を持ってきて」という意味になります。
一番上の階層から書くので、住所が長くなりがちですが、誰がどこから読んでも「ああ、あの場所のことね」と分かる、最も確実で間違いのない方法です。
2. 相対インポート (Relative Import)
これは、「今自分がいる場所から見た、相対的な位置関係」で指定する方法です。
「隣の部屋」や「一つ上の階層」といった指定の仕方をします。
この方法では「ドット(.)」を使います。
.(ドット1個): 「今、自分と同じ階層(フォルダ)にいる」..(ドット2個): 「一つ上の階層(フォルダ)にいる」
例えば、company/products/tools.py の中から、すぐ隣(同じ階層)にある ではなく、一つ上の company 階層にある staff.py を読み込みたいとしましょう。
(tools.py から staff.py を見ると、staff.py は親の company フォルダにいますね)
# company/products/tools.py の中
from .. import staff
これは、「今いる products フォルダから一つ上がって(company フォルダに行って)、そこにある staff 道具箱を持ってきて」という意味になります。
どっちを使うべき? メリット・デメリット
では、この「絶対」と「相対」、どちらを使うのが良いのでしょうか?
絶対インポート
- メリット:
- 住所が明確で、どこから読んでも迷わない。
- ファイルの位置を移動させたときも、プロジェクトの入り口からのパスが変わらなければ修正が不要。
- デメリット:
- 階層が深くなると、
import a.b.c.d.eのように記述がとても長くなる。
- 階層が深くなると、
相対インポート
- メリット:
- 記述が短くて済む。
- パッケージ(倉庫)の名前を丸ごと変えたとき、パッケージ内部の import 文(相対パス)は修正しなくても動く。
- デメリット:
- 「今、自分はどこにいるんだっけ?」と、現在の位置を把握していないと混乱しやすい。
.がいくつも続くと(from ...module)、非常に読みにくくなる。- そのファイルを直接実行しようとすると、相対インポートはエラー(ImportError)を起こします。
まとめと今後の学習指針
Pythonのインポート階層、いかがでしたか?
- Pythonは
sys.pathという「住所録」に書かれた場所を探しに行く。 __init__.pyファイルは、フォルダを「パッケージ(倉庫)」として認識させるための目印。- 住所の書き方には、入口から全部書く「絶対インポート」と、今いる場所から指定する「相対インポート」がある。
初心者のうちは、まず「絶対インポート」だけを使うことを強くお勧めします!
それが一番混乱しない、安全な道です。
そして、なぜ import が失敗するのか分からなくなったときは、sys.path の中身を print してみて、「今Pythonがどこを探しに行っているのか」を実際に目で見て確認するクセをつけましょう。
さあ、これからはエラーを恐れずに、便利なモジュールやパッケージをどんどん活用してみてください!
セイ・コンサルティング・グループの新人エンジニア研修のメニューへのリンク
投稿者プロフィール
- 代表取締役
-
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。
最新の投稿
山崎講師2025年10月26日Pythonのimport完全ガイド!パッケージとモジュールの階層構造をスッキリ理解しよう
山崎講師2025年10月26日Python関数の引数の罠!正しい順番をマスターしてエラーを回避しよう
山崎講師2025年10月26日Pythonの「浅いコピー」と「深いコピー」の違いとは?コピーの罠を徹底解説!
山崎講師2025年10月26日VSCodeを自分好みに育てる!新人エンジニアのためのsettings.json徹底ガイド