はじめに
Pythonでプログラミングをしていると、当たり前のように使っているpip installコマンド。
このコマンド一つで、便利なライブラリがすぐに使えるようになります。
しかし、**結局、pipは何をどこにダウンロードして、どうやってPythonがそれを見つけているのか?**を詳しく知っている人は意外と少ないかもしれません。
普段は意識しなくても開発は進められますが、
以下のような場面では内部の仕組みを理解していると役立ちます。
- ライブラリをインストールしたはずなのに
ModuleNotFoundErrorが出るというトラブルの解決 - 特定のプロジェクトだけで自作ライブラリを使い回したいときの構成
- 複数のライブラリのバージョン競合(依存関係)で詰まったときの原因究明
この記事では、pip installが内部でどのような処理を行っているのかを、できるだけシンプルに解説します。
pip installの基本的な流れ
pip installを実行したとき、内部では大きく分けて
「探す」「置く」「つなげる」の3つのステップが行われています。
1. PyPIからパッケージをダウンロード(探す)
まず、pipは PyPI(Python Package Index) という、
世界中のライブラリが集まる倉庫へ繋ぎにいきます。
- 指定されたバージョン(指定がなければ最新版)を探す。
- 自分のOS(Windows/Mac/Linux)やPythonのバージョンに合った
ビルド済みファイル(Wheel)を優先的に探します。
Wheelファイルとは、、、
ライブラリなどのプログラムはコード状態だけだと動かず、
自分のOSやPythonのバージョンにあった機械語に翻訳する必要があります。事前に翻訳しておいたものが
wheelファイルです。
2. site-packageディレクトリに配置(置く)
ダウンロードしたファイル(.whlファイルなど)を解凍し、中身を特定のフォルダにコピーします。
その行き先がsite-packagesです。
これが「インストールされた」という状態の実体です。
ちなみに、site-packageがどこにあるのかは次のコマンドで確認できます。
# PATHがどこに通っているか確認できる
python -m site
# 仮想環境だと例えば
# apps/.venv/lib/python3.12/site-packages
# $ ls .venv/lib/python3.12/site-packages
numpy pip
numpy-2.4.1.dist-info pip-24.0.dist-info
3. Pythonがライブラリを見つける仕組み(つなげる)
なぜimportするだけで、コピーしたファイルが読み込まれるのでしょうか?
それは、Pythonが起動する時に**ライブラリを探しに行くリスト(検索パス)**を持っているからです。
このリストはsys.pathと呼ばれます。
よくパスが通っている、通っていないなどの文脈のあれです。
- Pythonを実行する。
-
import numpyと書かれているのを見つける。 -
sys.pathに登録されているフォルダ(site-packagesなど)を上から順番に覗く。 -
numpyというフォルダを見つけたら読み込む!
このように、pipはPythonの検索ルート上にあるsite-packagesに、物理的にファイルを置くという非常にシンプルな作業を自動化してくれているのです。
「ビルド済み(Wheel)」と「ソースビルド」の違い
pip installをしたとき、一瞬で終わることもあれば、
数分間画面が止まった挙句に赤い文字でエラーが出ることもあります。
この差は、「完成品」をダウンロードしているか、「材料」から組み立てているかの違いにあります。
Wheel (.whl):手間いらずの「完成品」
多くのメジャーなライブラリは、Wheel という形式で PyPI にアップロードされています。
これはすでにコンパイル(コンピュータが読める形式に変換)が終わっている「ビルド済み」のファイルです。
ダウンロードしてsite-packageに解凍・配置するだけなのですぐ終わるのがメリットです。
たとえば、numpy-1.26.0-cp310-cp310-manylinux_2_17_x86_64.whlのようなファイル名になっており、Python3.10用の、64bit Linux用の完成品といった情報が含まれています。
sdist (.tar.gz):現場で作る「ソースビルド」
一方で、自分の環境(OS、Pythonのバージョン、CPUアーキテクチャ)にぴったりのWheelがPyPIにない場合、pipはsdist (Source Distribution)をダウンロードします。
これはソースコード、つまり「設計図と材料」だけの状態です。
このとき、あなたの手元のマシンで「ビルド(コンパイル)」が始まります。
CUDAなどの環境はソースビルドが必要になることが多い
特にGPUを使うライブラリ(PyTorchの拡張ライブラリや、特定の画像処理ライブラリなど)で、
このソースビルドが発生しやすいです。
- ハードウェアへの最適化: NVIDIAのGPUを使う場合、そのマシンのCUDAツールキットのバージョンやGPUの世代(アーキテクチャ)に合わせて、C++やCUDAのコードを最適にコンパイルする必要があります。
- 依存関係の複雑さ: 「CUDA11.8と12.1、両方の全パターンに対してWheelを用意する」のは非常に大変なため、特殊な構成の環境では「手元でコンパイルしてね」という形式になります。
開発者の強い味方:Editableモード(-e)の仕組み
ライブラリを使っているとき、
「このライブラリの中にデバッグ用のログを仕込みたい」とか、
「自作ライブラリを開発しながら、別のプロジェクトで動作確認したい」という場面があります。
しかし、通常の pip installでは、コードを書き換えても変更が反映されません。
なぜなら、インストールした瞬間のコードがsite-packagesにコピーされただけだからです。
そこで便利なのがEditableモード (-e) です。
コピーではなく、参照
通常インストールと Editableモードの違いを一言で言うと、
ファイルをコピーするか、場所を教えるだけにするかの違いです。
- 通常インストール(
pip install)- ソースコードを
site-packagesにコピーする - 元のソースを編集しても、
site-packages内のファイルは古いまま
- ソースコードを
- Editableモード(
pip install -e)- ファイルをコピーしない
- 代わりに「ソースがここにある」という参照情報だけを
site-packagesに保存する
内部では.pthファイルが活躍している
「参照を置く」と言っても、OSのシンボリックリンク(ショートカット)を貼っているわけではありません。
Python独自の .pth (Path Configuration File)という仕組みを使っています。
Editableモードでインストールすると、site-packagesの中に
(パッケージ名).pthという小さなテキストファイルが生成されます。
この中身を覗いてみると、あなたの開発フォルダの絶対パスが1行書かれているだけです。
- Pythonが起動する。
-
site-packagesを見に行く。 -
.pthファイルを見つける。 - 「あ、ここ(開発フォルダ)もライブラリの探し場所に追加しなきゃ」と認識する。
この仕組みのおかげで、開発フォルダでコードを書き換えた瞬間に、
次にimportしたときには最新のコードが読み込まれるようになります。
-e .とsetup.py developは何が違う?
昔の主流はpython setup.py developでした。
このコマンドも同じようにEditableモードで-e .と同じです。
ただ、現在はpip install -e .が推奨されています。
.の意味
pip install -e .の最後にあるドットは「現在のディレクトリ」を指します。
つまり、「今自分がいるこの開発フォルダを、Editableモードでインストールしてね」という意味になります。
まとめ
本記事では、
- pip installの内部の動き
- Wheelとソースビルド
- Editableモード
についてざっくり解説していきました。
単にコマンドを知っているだけでなく、
内部で「ファイルがどう動いているか」を知っていると、トラブルへの対応力が変わります。
- 「インポートできない?なら
sys.pathとsite-packagesを確認しよう」 - 「ビルドエラーが出た?なら C++ コンパイラや CUDA の設定を見直そう」
- 「コードを変更しても反映されない?なら
-eモードを使おう」
このように、一つ一つのエラーに対して、根拠を持って対処できるようになるはずです。