+ 作るログイン
図を読み込んでいます…
1 / 21
JS から来た人の Python ― どこから来て、なぜ動くのか / 全19章

Python 11:pip と PyPI:ライブラリはどこから来るのか

発行
アニメモ公式
版
第1版
改訂
コマ
全21

pip install requests の1行の裏で起きている6つの段階(PyPI に一覧を問い合わせる・版を選ぶ・依存を調べる・wheel をダウンロードしてハッシュを確かめる・site-packages に展開する・dist-info に記録する)を、パソコンとインターネットの舞台の上で小包を動かして1段ずつ見せます。wheel が zip であることを実際に開いて確かめ、そのあとの import requests が sys.path から見つかるまでをつなぎます。npm との違い、配布名と import 名の違い、transformers のコードと重みが別の場所から別のタイミングで届くことも説明します。

「入っていない」なら入れる。でも、どうやって?

第10章の tenki のコードを、Python を入れたばかりのパソコンで動かすと、こうなります。

$ python3 main.py
Traceback (most recent call last):
  File "main.py", line 1, in <module>
    import requests
ModuleNotFoundError: No module named 'requests'

第8章の言葉で言えば、「sys.path のどのフォルダを探しても、requests という名前のモジュールもパッケージも見つからなかった」というエラーです。直し方はよく知られています。

bash
python3 -m pip install requests

これで、第10章で開いた site-packages/requests/ が現れ、import requests が通るようになります。でも、この1行の裏で何が起きているのかは、ふわっとしたままのことが多いはずです。

疑問この章で見せるもの
どこから来た?インターネットの、どの住所から届くのか
何が届いた?届くファイルの形(実際に開いて見る)
どこに置かれた?パソコンの、どのフォルダか
なぜ import で見つかる?第8章の sys.path とのつながり

pip install の裏では、6つの段階が順番に進んでいます。この章では、それを1段ずつに分けて、図の上で小包を動かしながら見ていきます。

※2026年9月時点(Python 3.13・pip 25)の情報です。

  • JS から来た人の Python 11 ― pip と PyPI
  • 1 / 21
  • 「入っていない」なら入れる。でも、どうやって?
  • $ python3 main.py
  • Traceback (most recent call last):
  • どこから来た?(インターネットの、どこ?)
  • File "main.py", line 1, in <module>
  • import requests
  • 何が届いた?(ファイル? フォルダ?)
  • ModuleNotFoundError: No module named 'requests'
  • どこに置かれた?(パソコンの、どこ?)
  • $ python3 -m pip install requests
  • import requests は、なぜそれを見つける?
  • Successfully installed ... requests-2.34.2 ...
  • 1行打つだけで直る。でも、その1行の裏では6つの段階が順に進んでいる
  • この章では、それを1段ずつページに分けて、小包が動くところを見ていく
  • ひらめき
  • site-packages の requests/ は pip install で届いたもの。その1行を分解する。

一言でいうと:公開の倉庫から、zip の箱を取り寄せて棚に並べる

先に全体をたとえ話で押さえます。通販を思い浮かべてください。

通販Python正体
倉庫PyPI(パイピーアイ)Python のパッケージを誰でも公開でき、誰でも取れるサイト。pypi.org
届く箱wheel(ホイール、.whl)組み立て済みのパッケージ。中身は zip
取り寄せ係pip探す・選ぶ・運ぶ・並べる・記録するを全部やる道具
棚site-packagesimport が探しに来るフォルダ(第10章)

pip は、PyPI という倉庫に「requests をください」と注文し、届いた wheel という箱を開けて、中身を site-packages という棚に並べます。棚に並んだものは、第8章の仕組みで import がいつでも取りに行けます。sys.path の中に、最初から site-packages が入っているからです。

JavaScript の言葉に置き換えると、PyPI は npm レジストリ(npmjs.com)、pip は npm コマンド、site-packages は node_modules に当たります。ただし site-packages と node_modules には大きな違いがあり、それは後で説明します。

  • JS から来た人の Python 11 ― pip と PyPI
  • 2 / 21
  • 一言でいうと:公開の倉庫から、zip の箱を取り寄せて棚に並べる
  • 店
  • 荷物
  • ダウンロード
  • フォルダ
  • PyPI
  • wheel(.whl)
  • pip
  • site-packages
  • 公開の倉庫
  • 届く箱
  • 取り寄せ係
  • 棚
  • 誰でも上げ、誰でも取れる
  • 中身は zip
  • 探す・運ぶ・並べる
  • import が探しに来る
  • 通販でたとえると:倉庫(PyPI)にある商品を、係(pip)が注文して、届いた箱(wheel)を開けて棚に並べる
  • 棚に並んだものは、import がいつでも取りに行ける(第8章の sys.path に site-packages が入っている)
  • ひらめき
  • PyPI=倉庫、wheel=箱(中身は zip)、site-packages=棚、pip=取り寄せて並べる係。

登場人物:あなたのパソコンと、インターネットの向こう

これから何度も使う舞台を紹介します。

場所登場人物役割
あなたのパソコンsite-packages(緑)ライブラリを置く棚。例:/Users/you/tenki/.venv/lib/python3.13/site-packages/
あなたのパソコンターミナルあなたが python3 -m pip install requests と打つ場所
あなたのパソコンpip注文を受けて、取り寄せから記録までを行う
インターネットPyPI(pypi.org)どんなパッケージの、どんな版とファイルがあるかの一覧を配る
インターネットfiles.pythonhosted.orgファイル本体(wheel など)が置いてある場所

1つ意外なことを言うと、pip 自身も、site-packages に入っているパッケージの1つです。作りたての環境の site-packages を開くと、pip/ と pip-25.3.dist-info/ だけが入っています。python3 -m pip と打つと、第2章で見た -m の働きで、「この python3 の site-packages にある pip というパッケージ」を実行しています。

PyPI の一覧と、ファイル本体の置き場が別の住所になっているのも覚えておいてください。一覧は pypi.org、ファイルは files.pythonhosted.org から届きます。

  • JS から来た人の Python 11 ― pip と PyPI
  • 3 / 21
  • 登場人物:あなたのパソコンと、インターネットの向こう
  • あなたのパソコン
  • インターネット
  • site-packages/
  • ターミナル
  • ターミナル
  • PyPI(pypi.org)
  • pip install requests
  • 店
  • パッケージの一覧を配る
  • ダウンロード
  • pip
  • python3 -m pip
  • ディスク
  • files.pythonhosted.org
  • ファイル本体の置き場
  • site-packages は、最初はほぼ空(pip 自身だけが入っている)。pip も、実は site-packages の中のパッケージ
  • PyPI は一覧(どんな版とファイルがあるか)を配り、ファイル本体は files.pythonhosted.org から届く
  • ひらめき
  • 左があなたのパソコン、右がインターネット。以下、この舞台の上で小包を動かしていく。

① PyPI に問い合わせる:「requests のファイル一覧をください」

最初の段階です。pip は、次の URL を読みに行きます。

https://pypi.org/simple/requests/

これは PyPI の Simple API(シンプル API)と呼ばれる窓口で、パッケージの名前ごとに1ページあります。ブラウザで開いてみると、真っ白な画面にファイル名のリンクがずらりと並んでいるのが見えます。実際に返ってくる情報を、1ファイル分だけ抜き出すとこうなります。

項目値
ファイル名requests-2.34.2-py3-none-any.whl
URLhttps://files.pythonhosted.org/packages/.../requests-2.34.2-py3-none-any.whl
対応する Python>=3.10
ハッシュsha256=2a0d60c1...
大きさ73,075 バイト

requests なら、2011年ごろの古い版から最新の 2.34.2 まで、すべての版のファイルがこの一覧に載っています。この時点では、まだ何もダウンロードしていません。「何があるか」を知っただけです。

npm も同じように、まずレジストリ(registry.npmjs.org)にパッケージの情報を問い合わせます。倉庫の名前が違うだけで、最初の一歩は同じです。

  • JS から来た人の Python 11 ― pip と PyPI
  • 4 / 21
  • ① PyPI に問い合わせる:「requests のファイル一覧をください」
  • あなたのパソコン
  • インターネット
  • site-packages/
  • ターミナル
  • ターミナル
  • PyPI(pypi.org)
  • pip install requests
  • 店
  • 一覧をください
  • パッケージの一覧を配る
  • ダウンロード
  • pip
  • python3 -m pip
  • ディスク
  • files.pythonhosted.org
  • ファイル本体の置き場
  • GET /simple/requests/
  • この一覧のページを「Simple API」と呼ぶ。ブラウザで開くと、ファイルへのリンクがずらりと並んでいる
  • リンクには、ファイルの URL・対応する Python の版(>=3.10)・ハッシュ(sha256)が付いている
  • ひらめき
  • pip は https://pypi.org/simple/requests/ を読みに行く。返ってくるのは全部の版とファイルの一覧。

② 版を選ぶ:条件に合う、いちばん新しいもの

一覧を受け取った pip は、どのファイルを使うかを決めます。決め方は2段です。

決めること決め方
どの版か条件を満たすもののうち、いちばん新しい版。何も指定しなければ最新版(2.34.2)
どのファイルかその版のファイルのうち、この Python・この OS で使えるもの。wheel があれば wheel を優先

版の条件は、pip install "requests>=2.30,<3" のように自分で付けることもできます(書き方は第13章)。また、すでに入っていて条件を満たしているなら、pip は何もしません。上げたいときは --upgrade を付けます。

ファイルの種類は2つあります。

種類拡張子中身
wheel.whl組み立て済み。開いて置くだけで使える
sdist(ソース配布).tar.gz作る前の材料。入れる側で組み立て(ビルド)が要る

「この Python・この OS で使えるか」は、wheel のファイル名に書かれたタグで判断します。requests の py3-none-any は「Python 3 ならどれでも、どの OS でも」という意味なので、誰のパソコンでも選ばれます。C 言語で書かれた部品を含むライブラリ(numpy や pillow など)は、OS や Python の版ごとに別々の wheel が用意されていて、pip は自分に合うものを選びます。

  • JS から来た人の Python 11 ― pip と PyPI
  • 5 / 21
  • ② 版を選ぶ:条件に合う、いちばん新しいもの
  • あなたのパソコン
  • インターネット
  • site-packages/
  • ターミナル
  • ターミナル
  • PyPI(pypi.org)
  • pip install requests
  • 店
  • ファイル一覧
  • パッケージの一覧を配る
  • ダウンロード
  • pip
  • python3 -m pip
  • ディスク
  • files.pythonhosted.org
  • ファイル本体の置き場
  • 2.34.2 の wheel に決定
  • … 2.34.1 / 2.34.2(最新)
  • requests-2.34.2-py3-none-any.whl
  • requests-2.34.2.tar.gz(ソース)
  • wheel(組み立て済みの箱)と sdist(.tar.gz・ソースの箱)が両方あれば、pip は wheel を選ぶ
  • py3-none-any =「Python 3 ならどれでも・どの OS でも」。OS ごとに別の wheel があるライブラリもある
  • ひらめき
  • 指定が無ければ最新版。さらに「この Python とこの OS で使えるファイル」を、名前のタグで選ぶ。

③ 依存を調べる:METADATA だけ先に取り寄せる

第10章で、requests は urllib3 などの別のライブラリを使っていることを見ました。requests だけを入れても、動きません。そこで pip は、requests が何を必要としているかを調べます。

調べるのに、73KB の wheel 全体を取り寄せる必要はありません。PyPI は、wheel の中の METADATA というファイルだけを、別に取り寄せられるようにしています(4.8KB)。実際の pip の出力にも Downloading requests-2.34.2-py3-none-any.whl.metadata (4.8 kB) という行が出ます。

METADATA の中の、依存を書いた行はこうです。

Requires-Dist: charset_normalizer<4,>=2
Requires-Dist: idna<4,>=2.5
Requires-Dist: urllib3<3,>=1.26
Requires-Dist: certifi>=2023.5.7

pip は、この4つについても①②を同じように繰り返します。さらにそれぞれの依存の依存…とたどり、全員の条件を同時に満たす版の組み合わせを決めます。これを依存の解決(resolve)と呼びます。

図では、依存の4つを札で表しました。この札が、あとで棚に並ぶことになります。npm でも、package.json の dependencies をたどって同じことをしています。

  • JS から来た人の Python 11 ― pip と PyPI
  • 6 / 21
  • ③ 依存を調べる:METADATA だけ先に取り寄せる
  • あなたのパソコン
  • インターネット
  • site-packages/
  • ターミナル
  • ターミナル
  • PyPI(pypi.org)
  • pip install requests
  • 店
  • METADATA
  • パッケージの一覧を配る
  • ダウンロード
  • pip
  • python3 -m pip
  • ディスク
  • files.pythonhosted.org
  • ファイル本体の置き場
  • requests が要るもの
  • urllib3/
  • idna/
  • charset_normalizer/
  • certifi/
  • METADATA(4.8KB)の Requires-Dist: urllib3<3,>=1.26 / idna<4,>=2.5 / charset_normalizer<4,>=2 / certifi
  • 依存の依存…とたどって、全員の条件を満たす版の組み合わせを決める。これを「依存の解決」と呼ぶ
  • ひらめき
  • requests は4つのライブラリが無いと動かない。pip はそれも同じ①②で探し、一緒に入れる。

④ wheel をダウンロードする:ハッシュで中身を確かめる

入れるものが全部決まったら、いよいよファイル本体を取り寄せます。取り寄せ先は、①の一覧に書かれていた files.pythonhosted.org の URL です。

届くもの大きさ
requests-2.34.2-py3-none-any.whl73KB
urllib3-2.8.0-py3-none-any.whl135KB
certifi-2026.7.22-py3-none-any.whl136KB
idna-3.20-py3-none-any.whl69KB
charset_normalizer-3.5.2-cp313-cp313-…manylinux….whl254KB(Linux の場合)

charset_normalizer だけ名前が長いのは、C で速くした部品を含んでいて、Python の版(cp313)と OS ごとに別の wheel があるからです。macOS では macOS 用の wheel が選ばれます。

届いたファイルは、①の一覧に載っていた sha256 ハッシュと照合されます。1バイトでも違えば、pip はそのファイルを使わずに止まります。途中で壊れたファイルを棚に並べないための仕組みです。

一度取り寄せたファイルは、pip のキャッシュにも保存されます。macOS なら ~/Library/Caches/pip、Linux なら ~/.cache/pip です(python3 -m pip cache dir で確かめられます)。2回目からは出力が Using cached ... になり、通信せずに済みます。

  • JS から来た人の Python 11 ― pip と PyPI
  • 7 / 21
  • ④ wheel をダウンロードする:ハッシュで中身を確かめる
  • あなたのパソコン
  • インターネット
  • site-packages/
  • ターミナル
  • ターミナル
  • PyPI(pypi.org)
  • pip install requests
  • 店
  • パッケージの一覧を配る
  • ダウンロード
  • pip
  • requests.whl
  • python3 -m pip
  • ディスク
  • files.pythonhosted.org
  • ファイル本体の置き場
  • 73KB・sha256 を照合
  • urllib3/
  • idna/
  • charset_normalizer/
  • certifi/
  • 届くのは requests-2.34.2-py3-none-any.whl(73KB)。依存の4つも同じように届く
  • 2回目からは pip のキャッシュ(macOS なら ~/Library/Caches/pip)から使う。出力が「Using cached」になる
  • ひらめき
  • 5つの wheel が files.pythonhosted.org から届く。一覧のハッシュと合わなければ、使わずに止まる。

wheel の正体は zip:中身を開いて確かめる

届いた .whl とは何なのか、実際に開いてみます。Python の仕様(packaging.python.org の Binary distribution format)には、wheel は「特別な形式のファイル名と `.whl` 拡張子を持つ ZIP 形式のアーカイブ」と書かれています。本当かどうか、標準ライブラリの zipfile で中身を一覧してみます。

$ python3 -m zipfile -l requests-2.34.2-py3-none-any.whl
File Name                                   Modified             Size
requests/__init__.py                        2026-05-14 19:21:52  5922
requests/api.py                             2026-05-14 19:21:52  7152
requests/sessions.py                        2026-05-14 19:21:52 34248
...
requests-2.34.2.dist-info/METADATA          2026-05-14 19:21:52  4806
requests-2.34.2.dist-info/WHEEL             2026-05-14 19:21:52    91
requests-2.34.2.dist-info/RECORD            2026-05-14 19:21:52  2027

zip として普通に開けました。file コマンドで調べても Zip archive data と出ます。中身は、第10章で見た `requests/` フォルダそのものと、requests-2.34.2.dist-info/ という控えのフォルダの2つです。つまり wheel は、「site-packages にそのまま置ける形に並べたフォルダを、zip で固めたもの」です。

ファイル名は、仕様で {配布名}-{版}-{Python タグ}-{ABI タグ}-{プラットフォームタグ}.whl と決まっています。図の表のとおり、requests の py3-none-any は「Python 3 用・C の部品なし・どの OS でも」です。npm の .tgz(tar を gzip で固めたもの)と、立場はほぼ同じです。

  • JS から来た人の Python 11 ― pip と PyPI
  • 8 / 21
  • wheel の正体は zip:中身を開いて確かめる
  • $ python3 -m zipfile -l requests-2.34.2-py3-none-any.whl
  • ファイル名の読み方(仕様で決まっている)
  • requests/__init__.py
  • requests/api.py
  • 部分
  • 意味
  • requests/sessions.py
  • requests/ …(ほか .py が16個)
  • requests
  • 配布名
  • requests-2.34.2.dist-info/METADATA
  • requests-2.34.2.dist-info/WHEEL
  • 2.34.2
  • 版
  • requests-2.34.2.dist-info/RECORD
  • py3
  • Python 3 用
  • requests-2.34.2.dist-info/top_level.txt
  • requests-2.34.2.dist-info/licenses/LICENSE
  • none
  • C の部品なし
  • any
  • どの OS でも
  • file コマンドで見ても「Zip archive data」と出る
  • ひらめき
  • 拡張子が .whl なだけの zip。中にはそのまま site-packages に置ける形でフォルダが入っている。

⑤ site-packages に展開する:依存から順に棚へ

いよいよ棚に並べます。wheel の仕様では、インストールの手順を「展開(Unpack)」と「配置(Spread)」と呼んでいます。やっていることは、次のとおりです。

手順中身
展開zip を開いて、中のフォルダを site-packages にそのまま置く
配置コマンドとして使うファイルがあれば bin/ に置く(requests には無い)
仕上げ置いた .py を .pyc(第1章のバイトコード)にしておく。__pycache__/ ができる

並べる順番は、依存が先です。pip の出力にも Installing collected packages: urllib3, idna, charset_normalizer, certifi, requests と、requests が最後に書かれています。requests が棚に並んだ瞬間に、requests が使う urllib3 がまだ無い、ということが起きないようにするためです。

図では、③で出てきた依存の札が、そのまま棚に入りました。棚には requests/ と、その隣に requests-2.34.2.dist-info/ も並んでいます。

「インストール」というと、何か複雑な登録作業をしている気がしますが、Python のライブラリのインストールは、ほとんど「zip を開いてフォルダに置く」だけです。だから第10章で見たとおり、site-packages の中はエディタで開けば読める普通のファイルなのです。

  • JS から来た人の Python 11 ― pip と PyPI
  • 9 / 21
  • ⑤ site-packages に展開する:依存から順に棚へ
  • あなたのパソコン
  • インターネット
  • site-packages/
  • ターミナル
  • ターミナル
  • 店
  • PyPI(pypi.org)
  • urllib3/
  • pip install requests
  • パッケージの一覧を配る
  • idna/
  • charset_normalizer/
  • ダウンロード
  • pip
  • python3 -m pip
  • ディスク
  • files.pythonhosted.org
  • certifi/
  • ファイル本体の置き場
  • requests/
  • zip を開いて棚に置く
  • requests-2.34.2.dist-info
  • Installing collected packages: urllib3, idna, charset_normalizer, certifi, requests(依存が先)
  • 置いたあと .py を .pyc にしておく(__pycache__/ ができる)。これで import が速くなる
  • ひらめき
  • zip を開いて、中のフォルダを site-packages にそのまま置く。インストールとは、ほぼこれだけ。

⑥ dist-info に記録する:何を入れたかの控え

最後の段階は記録です。棚に並んだ requests-2.34.2.dist-info/ フォルダが、その控えです。中を見てみます。

ファイル中身誰が使う
METADATA名前・版・説明・依存(Requires-Dist)pip show、依存の確認
RECORD入れた全ファイルのパスとハッシュの一覧pip uninstall(これを見て消す)
INSTALLER入れた道具の名前。中身は pip の3文字他の道具との区別
REQUESTEDあなたが直接頼んだ印(依存として入ったものには無い)「自分で入れたもの」の区別
WHEELwheel の形式の版などpip
top_level.txtimport するときの名前(requests)名前を調べるとき

METADATA・RECORD・WHEEL は wheel の中に最初から入っていて、INSTALLER と REQUESTED はインストールのときに pip が書き足します。RECORD にも、__pycache__/ の .pyc など、インストールで増えたファイルが追記されます。

pip は「何が入っているか」を覚えておくための特別なデータベースを持っていません。*site-packages に並んだ `.dist-info/ フォルダそのものが、入っているものの台帳**です。pip list` はこのフォルダを数えて表にしているだけです。

  • JS から来た人の Python 11 ― pip と PyPI
  • 10 / 21
  • ⑥ dist-info に記録する:何を入れたかの控え
  • site-packages/
  • $ ls site-packages/requests-2.34.2.dist-info/
  • METADATA 名前・版・依存(Requires-Dist)・説明
  • urllib3/
  • RECORD 入れた全ファイルの一覧とハッシュ
  • idna/
  • INSTALLER 入れた道具の名前(中身は pip)
  • REQUESTED あなたが直接頼んだ印(依存には無い)
  • charset_normalizer/
  • WHEEL wheel の形式の情報
  • certifi/
  • top_level.txt import 名(requests)
  • requests/
  • pip list・pip show は、ここを読んで答えている
  • requests-2.34.2.dist-info
  • pip uninstall は RECORD に書かれたファイルだけを消す
  • ひらめき
  • dist-info/ は「この版を、このファイルで入れた」という控え。pip はここを読む。

実際の出力:6つの段階が、そのまま並んでいる

ここまでの6段を頭に入れて、実際の pip install の出力を読んでみます(Python 3.13・pip 25.3 で、キャッシュが無い状態で実行したもの。長い行は一部省略)。

$ python3 -m pip install requests
Collecting requests
  Downloading requests-2.34.2-py3-none-any.whl.metadata (4.8 kB)
Collecting charset_normalizer<4,>=2 (from requests)
  Downloading charset_normalizer-3.5.2-cp313-...whl.metadata (46 kB)
Collecting idna<4,>=2.5 (from requests)
Collecting urllib3<3,>=1.26 (from requests)
Collecting certifi>=2023.5.7 (from requests)
Downloading requests-2.34.2-py3-none-any.whl (73 kB)
Downloading charset_normalizer-3.5.2-cp313-...whl (254 kB)
Downloading idna-3.20-py3-none-any.whl (69 kB)
Downloading urllib3-2.8.0-py3-none-any.whl (135 kB)
Downloading certifi-2026.7.22-py3-none-any.whl (136 kB)
Installing collected packages: urllib3, idna, charset_normalizer, certifi, requests
Successfully installed certifi-2026.7.22 charset_normalizer-3.5.2 idna-3.20 requests-2.34.2 urllib3-2.8.0
出力の行段階
Collecting requests①② 一覧を読み、版を選ぶ
Downloading ....whl.metadata③ METADATA だけ先に取り寄せる
Collecting ... (from requests)③ 依存も①②を繰り返す
Downloading ....whl (73 kB)④ wheel 本体を取り寄せる
Installing collected packages⑤⑥ 依存から順に棚に並べて記録する

出力は呪文ではなく、6つの段階の実況中継だったのです。図の①〜⑥の説明は、この本で書き足したものです。

  • JS から来た人の Python 11 ― pip と PyPI
  • 11 / 21
  • 実際の出力:6つの段階が、そのまま並んでいる
  • $ python3 -m pip install requests
  • Collecting requests ①② 一覧を読み、版を選ぶ
  • Downloading requests-2.34.2-py3-none-any.whl.metadata (4.8 kB)
  • Collecting charset_normalizer<4,>=2 (from requests) ③ 依存も同じように
  • Collecting idna<4,>=2.5 (from requests)
  • Collecting urllib3<3,>=1.26 (from requests)
  • Collecting certifi>=2023.5.7 (from requests)
  • Downloading requests-2.34.2-py3-none-any.whl (73 kB) ④ 本体を取り寄せる
  • Downloading urllib3-2.8.0-py3-none-any.whl (135 kB) …ほか3つ
  • Installing collected packages: urllib3, idna, charset_normalizer, certifi, requests ⑤⑥
  • Successfully installed certifi-2026.7.22 charset_normalizer-3.5.2 idna-3.20 requests-2.34.2 urllib3-2.8.0
  • 行の途中の説明(①〜⑥)はこの本で書き足したもの。実際の出力には無い
  • ひらめき
  • pip の出力を上から読むと、問い合わせ→依存→ダウンロード→展開の順が見える。

そして import requests:第8章の仕組みで、棚から見つかる

棚に並んだあとで import requests と書くと、何が起きるか。これは第8章でやったことそのままです。図の小包が、main.py から棚の requests/ にたどり着きます。

python
>>> import sys
>>> for p in sys.path: print(p)

/Users/you/tenki/.venv/lib/python313.zip
/Users/you/tenki/.venv/lib/python3.13
/Users/you/tenki/.venv/lib/python3.13/lib-dynload
/Users/you/tenki/.venv/lib/python3.13/site-packages

(先頭の空行は、今いるフォルダを表す空の文字列です。標準ライブラリの3行は、実際には venv ではなく Python 本体の場所を指します。)

順番起きること
1sys.modules にまだ requests が無いことを確かめる
2sys.path を上から探す。今のフォルダにも、標準ライブラリにも requests は無い
3最後の site-packages で requests/ を見つける
4requests/__init__.py を上から実行する(第10章で中身を見たもの)
5できたモジュールに requests という名前を付ける

site-packages は、Python が起動するときに自動で sys.path に加えられます。だから pip は `sys.path` をいじる必要がなく、決まった棚に置くだけで、import から見えるようになるのです。確かめたいときは、print(requests.__file__) で、読まれたファイルのパスを表示できます。

  • JS から来た人の Python 11 ― pip と PyPI
  • 12 / 21
  • そして import requests:第8章の仕組みで、棚から見つかる
  • あなたのパソコン
  • site-packages/
  • >>> import sys; sys.path
  • 書類
  • main.py
  • ['', ← 今のフォルダ
  • urllib3/
  • import requests
  • '.../lib/python313.zip',
  • '.../lib/python3.13', ← 標準
  • idna/
  • '.../lib/python3.13/lib-dynload',
  • '.../site-packages'] ← ここ
  • charset_normalizer/
  • import requests
  • certifi/
  • 上から順に探し、site-packages で requests/ を見つける
  • requests/
  • requests/__init__.py を上から実行(第10章)
  • requests.__file__ で、見つかった場所を確かめられる
  • requests-2.34.2.dist-info
  • ひらめき
  • sys.path の中に site-packages がある。だから棚に置いただけで import できる。

どの site-packages に入る?:pip を動かしている Python のもの

ここで大事なことがあります。site-packages は、Python ごとに1つずつあります。第2章で見たように、1台のパソコンに複数の Python が同居していることはよくあります。

pip が棚に並べるのは、その pip を動かしている Python の site-packagesです。

打ったコマンド入る棚
python3 -m pip install requestspython3 の site-packages(確実)
python3.12 -m pip install requestspython3.12 の site-packages
pip install requestsPATH で最初に見つかった pip の持ち主の site-packages(見た目では分からない)

pip とだけ打つと、第2章の PATH の順番で最初に見つかった pip というコマンドが動きます。それがどの Python に属しているかは、コマンドを見ても分かりません。その結果、「入れたのに No module named」が起きます。図の右の Python には、requests が入っていないのです。

python3 -m pip と書けば、「今 python3 と打って動く Python の pip」と決まるので、スクリプトを動かす python3 と棚が必ず一致します。この本がずっと python3 -m pip と書いているのはそのためです。入った場所は、python3 -m pip show requests の Location: の行で確かめられます。

  • JS から来た人の Python 11 ― pip と PyPI
  • 13 / 21
  • どの site-packages に入る?:pip を動かしている Python のもの
  • Python 3.13(/opt/homebrew/bin/python3)
  • 別の Python(例:python3.12)
  • CPU
  • フォルダ
  • CPU
  • フォルダ
  • python3
  • site-packages
  • python3.12
  • site-packages
  • requests がある
  • requests は無い
  • python3 -m pip install requests
  • python3.12 main.py
  • → この python3 の棚に入る
  • → No module named 'requests'
  • pip だけで打つと、PATH で最初に見つかった pip が動く。それがどの Python のものかは見た目では分からない
  • python3 -m pip と書けば「この python3 の pip」と確定する(第2章の -m)。pip show の Location で確かめられる
  • ひらめき
  • site-packages は Python ごとに1つ。pip は「自分を動かしている Python」の棚に入れる。

npm と比べる:node_modules はプロジェクトに、site-packages は Python に

ここで、npm との一番大きな違いが見えてきます。

npmpip
倉庫npm レジストリ(npmjs.com)PyPI(pypi.org)
届く箱.tgz(tar+gzip).whl(zip)
置き場所プロジェクトの node_modules/その Python の site-packages/
探し方今のフォルダから上へ node_modules/ をたどるsys.path を上から探す
記録プロジェクトの package.json と package-lock.jsonsite-packages の *.dist-info/ だけ

npm install axios は、今いるプロジェクトのフォルダの中に node_modules/ を作って入れ、package.json に「axios を使う」と書き足します。プロジェクトごとに別々の棚があるので、アプリAは axios 1.6、アプリBは axios 1.7、ということが自然にできます。

pip install requests は、プロジェクトのフォルダには何も作りません。その Python の棚に入れるだけで、「このプロジェクトは requests を使う」という記録もどこにも残りません。つまり、既定のままでは、同じ Python を使う全部のプロジェクトが1つの棚を共有しています。

これが困る場面と、その解決策(プロジェクトごとに棚を分ける仮想環境)が次の第12章です。記録を残す話(requirements.txt や pyproject.toml)は第13章で扱います。

  • JS から来た人の Python 11 ― pip と PyPI
  • 14 / 21
  • npm と比べる:棚はプロジェクトごとか、Python ごとか
  • JS:npm install axios
  • Python:pip install requests
  • フォルダ
  • フォルダ
  • CPU
  • フォルダ
  • my-app/
  • node_modules/
  • python3
  • site-packages/
  • プロジェクト
  • このアプリ専用
  • Python 本体
  • 全プロジェクト共用
  • npm
  • pip
  • 倉庫
  • npm レジストリ(npmjs.com)
  • PyPI(pypi.org)
  • 置き場所
  • プロジェクトの node_modules/
  • その Python の site-packages/
  • 記録
  • package.json・package-lock.json
  • site-packages の dist-info だけ
  • ひらめき
  • npm は既定でプロジェクトの中に入れる。pip は既定で「その Python 全体」に1つの棚に入れる。

入れる名前と、import する名前は違うことがある

pip に渡す名前は、PyPI 上の配布名(第10章の「配布パッケージ」の名前)です。一方、import に書くのは、棚に置かれたフォルダの名前です。この2つは、たいてい同じですが、違うこともあります。

pip install(配布名)import(フォルダ名)中身
requestsrequestsHTTP で通信する
pillowPIL画像を扱う
scikit-learnsklearn機械学習
beautifulsoup4bs4HTML を読む
python-dateutildateutil日付の計算
PyYAMLyamlYAML を読む

実際に pillow の wheel を開くと、中に入っているのは PIL/ というフォルダと pillow-12.3.0.dist-info/ です。棚に置かれるのが PIL/ なので、import PIL と書きます。pillow は、昔の PIL というライブラリを引き継いだものなので、import 名が昔のまま残っているのです。

逆向きの間違いにも注意が要ります。pip install sklearn と打つと、PyPI にある sklearn という別物が見つかります。これは「scikit-learn を使ってください」と知らせるためだけに置かれたもので、今は入れようとするとエラーになります。import 名は、dist-info の top_level.txt にも書いてあります。

  • JS から来た人の Python 11 ― pip と PyPI
  • 15 / 21
  • 入れる名前と、import する名前は違うことがある
  • pip install(配布名)
  • import(フォルダ名)
  • 中身
  • requests
  • requests
  • HTTP で通信する
  • pillow
  • PIL
  • 画像を扱う(wheel の中は PIL/)
  • scikit-learn
  • sklearn
  • 機械学習
  • beautifulsoup4
  • bs4
  • HTML を読む
  • python-dateutil
  • dateutil
  • 日付の計算
  • PyYAML
  • yaml
  • YAML を読む
  • pip install sklearn は不可。PyPI の sklearn は「scikit-learn を使って」と知らせるための別物
  • import 名は dist-info の top_level.txt に書いてある。迷ったら PyPI のページの説明を見る
  • ひらめき
  • pip に渡すのは PyPI 上の「配布名」、import に書くのは中のフォルダの名前。一致しなくてもよい。

棚を見る・調べる・片付ける:pip list / show / uninstall

棚の中身を扱う3つのコマンドを覚えておきましょう。どれも、⑥で見た dist-info を読んだり使ったりしているだけです。

コマンドやること読むもの
python3 -m pip list棚に並んでいるものと版の一覧*.dist-info/ の名前と METADATA
python3 -m pip show requests1つの詳しい情報(場所・依存・誰に使われているか)METADATA
python3 -m pip uninstall requests棚から片付けるRECORD(書かれたファイルだけを消す)

pip show の Location: は、棚の場所そのものです。Requires: は requests が使うもの、Required-by: は requests を使っているもの(ここでは空)です。

pip uninstall requests は、requests の RECORD に書かれたファイルだけを消します。依存として一緒に入った urllib3 などは、残ります。 npm の npm uninstall が不要になった依存も片付けるのとは違います。「何を自分で入れて、何が依存で入ったのか」を分けて管理したくなりますが、それも第12・13章の仮想環境と依存の記録で解決します。

  • JS から来た人の Python 11 ― pip と PyPI
  • 16 / 21
  • 棚を見る・調べる・片付ける:pip list / show / uninstall
  • $ python3 -m pip list
  • $ python3 -m pip show requests
  • Package Version
  • Name: requests
  • certifi 2026.7.22
  • Version: 2.34.2
  • charset-normalizer 3.5.2
  • Location: /Users/you/tenki/.venv/lib/
  • idna 3.20
  • python3.13/site-packages
  • pip 25.3
  • Requires: certifi, charset_normalizer,
  • requests 2.34.2
  • idna, urllib3
  • urllib3 2.8.0
  • Required-by:
  • $ python3 -m pip uninstall requests # 依存(urllib3 など)は残る。自動では消えない
  • Successfully uninstalled requests-2.34.2
  • ひらめき
  • 3つとも、site-packages の dist-info を読んだり、RECORD の通りに消したりしているだけ。

import transformers ①:ライブラリ本体は、PyPI から site-packages へ

依頼者の最初の疑問に戻ります。「import transformers と書いて、なんでライブラリが入るの? どこから? ローカルに保存されてる?」

答えから言うと、`import transformers` と書いただけでは、何も入りません。先に pip install transformers で入れておく必要があり、そのとき起きることは requests とまったく同じ①〜⑥です。舞台を少し変えて、インターネットの側に Hugging Face Hub、パソコンの側に Hugging Face のキャッシュのフォルダを足しました。

項目transformers 5.17.0 の実物
届く wheeltransformers-5.17.0-py3-none-any.whl(12MB)
中身transformers/ フォルダと dist-info。.py が2,681個
主な依存huggingface_hub、tokenizers、safetensors、numpy、pyyaml など
置かれる場所site-packages/transformers/

ここで大事なのは、この wheel の中にはモデルの重み(学習済みの数値のファイル)が1つも入っていないことです。実際に開いて .safetensors や .bin を探しても、見つかりません。入っているのは、モデルを読み込み、動かすための Python のコードだけです。

また、計算の本体である PyTorch は、transformers の必須の依存には入っていません。pip install "transformers[torch]" のように、角かっこで「追加の組(extra)」を指定すると一緒に入ります。

  • JS から来た人の Python 11 ― pip と PyPI
  • 17 / 21
  • import transformers ①:コードは PyPI から
  • あなたのパソコン
  • インターネット
  • site-packages/
  • 店
  • PyPI(pypi.org)
  • transformers/
  • huggingface_hub/
  • tokenizers/
  • pip install
  • ライブラリ(コード)の倉庫
  • transformers.whl
  • ~/.cache/huggingface/hub/
  • 考える
  • Hugging Face Hub
  • モデル(重み)の倉庫
  • transformers 5.17.0 の wheel は 12MB・.py が2,681個。依存に huggingface_hub・tokenizers・safetensors など
  • 計算の本体 PyTorch は別に入れる(pip install "transformers[torch]" のように、追加の指定で一緒に入れられる)
  • ひらめき
  • pip install transformers で届くのは約2,700個の .py(12MB)。モデルの重みは1つも入っていない。

import transformers ②:重みは、初めて使った瞬間に Hub からキャッシュへ

では、重みはいつ、どこから来るのでしょうか。次のようなコードを初めて動かしたときです。

python
from transformers import pipeline

clf = pipeline("sentiment-analysis",
               model="distilbert/distilbert-base-uncased-finetuned-sst-2-english")
print(clf("I love this weather!"))

import transformers(や from transformers import pipeline)の時点では、まだ通信は起きません。モデルの名前を渡して読み込もうとした瞬間に、transformers は依存の huggingface_hub を使って、Hugging Face Hub(huggingface.co)からモデルのファイルを取り寄せます。PyPI とは別の、モデル専用の倉庫です。

項目実際の値
取り寄せ先huggingface.co の distilbert/distilbert-base-uncased-finetuned-sst-2-english
主なファイルmodel.safetensors(約268MB)、config.json、vocab.txt など
置かれる場所~/.cache/huggingface/hub/models--distilbert--distilbert-base-uncased-finetuned-sst-2-english/

2回目からは、このキャッシュから読むので通信しません。キャッシュの場所は、環境変数 HF_HOME(~/.cache/huggingface の部分)や HF_HUB_CACHE(hub の部分まで)で変えられます。大きなモデルを外付けのディスクに置きたいときに使います。

つまり「ローカルに保存されてる?」の答えは「はい。ただし2か所に、別々に」です。

  • JS から来た人の Python 11 ― pip と PyPI
  • 18 / 21
  • import transformers ②:重みは Hub から
  • あなたのパソコン
  • インターネット
  • site-packages/
  • 店
  • PyPI(pypi.org)
  • transformers/
  • huggingface_hub/
  • tokenizers/
  • ライブラリ(コード)の倉庫
  • from transformers import pipeline
  • clf = pipeline("sentiment-analysis",
  • ~/.cache/huggingface/hub/
  • model="distilbert/…-sst-2-english")
  • models--distilbert--…
  • model.safetensors 268MB
  • config.json・vocab.txt など
  • 考える
  • Hugging Face Hub
  • 重み 268MB
  • 初回だけ
  • モデル(重み)の倉庫
  • import transformers の時点では、まだ何も落ちてこない。モデルの名前を渡して読み込んだときに初めて通信する
  • 2回目からはキャッシュから読むので速い。場所は HF_HOME(または HF_HUB_CACHE)という環境変数で変えられる
  • ひらめき
  • from_pretrained を初めて呼ぶと、重みが Hub から ~/.cache に落ちてくる。

2つの道を並べる:コードは pip、重みは Hub

transformers を使うときの2つの道を、表に並べます。

transformers(コード)モデルの重み
どこからPyPI(pypi.org)Hugging Face Hub(huggingface.co)
いつpip install したときfrom_pretrained や pipeline で初めて読み込んだとき
誰が運ぶpiphuggingface_hub(transformers の依存のライブラリ)
どこへsite-packages/transformers/~/.cache/huggingface/hub/
大きさ(例)12MB268MB 〜 数十GB
消すにはpip uninstall transformershf cache rm や、キャッシュのフォルダを消す

キャッシュの中は、図の下のような作りになっています。blobs/ にファイル本体がハッシュの名前で入り、snapshots/<コミットID>/config.json は blobs/ の本体を指す参照(シンボリックリンク)です。refs/main には、今の最新のコミットID が書かれています。Hub のモデルは Git と同じように版(コミット)を持っているので、版ごとに snapshots/ の下のフォルダが分かれます。

この区別は、第12章の仮想環境で効いてきます。仮想環境を消して作り直すと、コードは消えますが、重みのキャッシュは残ります。キャッシュはホームフォルダにあって、どの仮想環境からも共有されるからです。何GBもの重みを、プロジェクトごとに落とし直さずに済むのはこのためです。

  • JS から来た人の Python 11 ― pip と PyPI
  • 19 / 21
  • 2つの道を並べる:コードは pip、重みは Hub
  • transformers(コード)
  • モデルの重み
  • どこから
  • PyPI(pypi.org)
  • Hugging Face Hub(huggingface.co)
  • いつ
  • pip install したとき
  • from_pretrained を初めて呼んだとき
  • 誰が運ぶ
  • pip
  • huggingface_hub(ライブラリ)
  • どこへ
  • site-packages/transformers/
  • ~/.cache/huggingface/hub/
  • 大きさ(例)
  • 12MB
  • 268MB〜数十GB
  • 消すには
  • pip uninstall transformers
  • hf cache rm(や、フォルダを消す)
  • ~/.cache/huggingface/hub/models--distilbert--…/ の中: blobs/(本体) refs/main snapshots/<コミットID>/
  • ひらめき
  • コードは PyPI→site-packages(pip install のとき)。重みは Hub→キャッシュ(初めて使うとき)。

よくある間違い:入れたのに見つからない

pip まわりのつまずきは、ほとんどが「pip を動かした Python と、スクリプトを動かした Python が違う」ことから来ます。

症状原因と直し方
入れたのに No module named 'requests'別の Python の棚に入れた。python3 -m pip で入れ、同じ python3 で動かす
error: externally-managed-environmentHomebrew や OS が管理している Python の棚には、直接入れられないようにしてある。仮想環境を作ってそこに入れる(第12章)
pip install sklearn でエラー配布名は scikit-learn。import 名と取り違えた
import PIL が見つからないpip install pillow を入れる
別のプロジェクトが急に壊れた棚は Python 全体で1つ。あるプロジェクトのために版を上げると、全員に効く(第12章)

2つ目の externally-managed-environment は、2023年ごろから macOS の Homebrew の Python や、Linux の多くのディストリビューションで出るようになったエラーです。Python の仕様(externally managed environments)で、「OS やパッケージ管理ツールが管理している Python の棚に、pip が勝手に書き込んで壊さないようにする」ための仕組みです。--break-system-packages で無理に通す方法もありますが、名前のとおり壊す可能性があるので、使わないでください。

迷ったら、次の2つを見比べます。python3 -c "import sys; print(sys.executable)" で今動いている Python の場所、python3 -m pip show requests の Location: で棚の場所です。

  • JS から来た人の Python 11 ― pip と PyPI
  • 20 / 21
  • よくある間違い:入れたのに見つからない
  • 症状
  • 原因と直し方
  • 入れたのに No module named
  • 別の Python に入れた。python3 -m pip で入れ、同じ python3 で動かす
  • error: externally-managed-environment
  • Homebrew などが管理する Python には直接入れられない。venv を作る(第12章)
  • pip install sklearn でエラー
  • 配布名は scikit-learn。import 名と配布名を取り違えた
  • import PIL が見つからない
  • pip install pillow を入れる(PIL という配布名ではない)
  • 別のプロジェクトが壊れた
  • 棚は Python 全体で1つ。版を上げると全員に効く(第12章)
  • 困ったら:python3 -c "import sys; print(sys.executable)" と python3 -m pip show 名前 の Location を見比べる
  • ひらめき
  • ほとんどは「pip を動かした Python」と「スクリプトを動かした Python」が違う。

まとめ:pip install は「取り寄せて、棚に並べて、控えを残す」

この章で分解したことをまとめます。

段やること実物
①PyPI に問い合わせるhttps://pypi.org/simple/requests/
②版とファイルを選ぶrequests-2.34.2-py3-none-any.whl(wheel を優先)
③依存を調べるMETADATA の Requires-Dist
④wheel をダウンロードfiles.pythonhosted.org から。sha256 を照合
⑤site-packages に展開zip を開いてフォルダを置く。依存が先
⑥dist-info に記録requests-2.34.2.dist-info/(RECORD・INSTALLER など)

そして import requests は、第8章の sys.path に最初から入っている site-packages で、置かれた requests/ を見つけるだけでした。transformers のようなライブラリでは、コードは PyPI から site-packages へ、モデルの重みは Hugging Face Hub から ~/.cache/huggingface へと、別の場所から、別のタイミングで届きます。

最後に、npm との比較で見えた問題が残っています。棚(site-packages)は Python 全体で1つです。tenki は requests の新しい版で作りたいのに、前に作った別のアプリは古い版でしか動かない。そんなとき、1つの棚ではどちらかが壊れます。次の第12章では、プロジェクトごとに専用の棚を作る仮想環境(venv)を、中身を並べて見ていきます。

  • JS から来た人の Python 11 ― pip と PyPI
  • 21 / 21
  • まとめ:pip install は「取り寄せて、棚に並べて、控えを残す」
  • 段
  • やること
  • 実物
  • ①
  • PyPI に問い合わせる
  • https://pypi.org/simple/requests/
  • ②
  • 版とファイルを選ぶ
  • requests-2.34.2-py3-none-any.whl
  • ③
  • 依存を調べる
  • METADATA の Requires-Dist
  • ④
  • wheel をダウンロード
  • files.pythonhosted.org(sha256 を照合)
  • ⑤
  • site-packages に展開
  • requests/ と依存のフォルダ
  • ⑥
  • dist-info に記録
  • requests-2.34.2.dist-info/RECORD など
  • 次の疑問:tenki は requests 2.34、別のアプリは古い版が要る。1つの棚でどうする?
  • ひらめき
  • でも棚が Python 全体で1つだと、プロジェクトごとに版を変えられない。次の第12章で箱を分ける。

0 件のコメント

読み込み中…

権利侵害・不適切な内容の連絡: [email protected]