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

Python 08:import の正体 ― 名前だけで、なぜどこから入るのか

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

import tenki・import json・import requests の3行が、パソコンの中のどのフォルダで見つかるのかを1段ずつ追いかけます。sys.modules(読み込み済みの棚)を見て、無ければ sys.path の名簿を上から探し、見つけたファイルを上から実行してモジュールを作り、名前を付ける。print(sys.path) と __file__ の実物、1回しか実行されない理由、from と as、if __name__ == "__main__"、Node の require や ESM との違い、自分のファイル名が本物を隠す事故まで扱います。

import と書くだけで、なぜ入るの? どこから?

第7章までで、tenki は関数とクラスを持つ1本のファイルになりました。そろそろファイルを分けたくなります。そのときに必ず書くのが import です。

python
import tenki
import json
import requests

ここで引っかかるのが自然です。3行とも名前しか書いていません。フォルダも、ファイル名も、URL も書いていません。それなのに、

書いたもの実際に使われるもの
import tenki自分で書いた tenki.py
import jsonPython に最初から付いてくる json(標準ライブラリ=Python と一緒に配られる部品集)
import requestspip install requests で入れたライブラリ(第11章)

と、まったく別の場所にあるものがちゃんと入ってきます。「どこから? ネットから? ローカルに保存されてる?」と思ったら、それは正しい疑問です。

答えを先に言うと、3つとも、あなたのパソコンのディスクの上にある、ただの .py ファイルです。import の瞬間にネットへ取りに行くことはありません。Python は「どのフォルダを、どの順番で探すか」という名簿を持っていて、そこに書かれたフォルダを上から順にのぞき、名前の合うファイルを見つけているだけです。

この章では、その名簿の実物を print で出し、3つの import がそれぞれ名簿の何段目で見つかるのかを、1段ずつ追いかけます。

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

  • JS から来た人の Python 08 ― import の正体
  • 1 / 30
  • import と書くだけで、なぜ入るの? どこから?
  • # main.py
  • 書類
  • tenki.py
  • import tenki
  • どこの?
  • 自分で書いたファイル
  • import json
  • import requests
  • どこの?
  • 本
  • json
  • Python に付いてくる(標準ライブラリ)
  • tenki.show(21)
  • どこの?
  • 荷物
  • requests
  • pip で入れたライブラリ
  • 3つとも、書き方はまったく同じ「import 名前」。フォルダもファイル名も書いていない
  • → Python の側に「どこを探すか」の決まった名簿がある。それを1つずつ見ていく
  • ひらめき
  • import は「名前」しか書いていない。場所を書いていないのに、なぜ見つかるのか。

一言でいうと:決まった順に棚を見て回る係

import の仕組みは、図書館の係にたとえるとわかりやすくなります。

あなたが「tenki という本をください」と頼むと、係は決まった順番の本棚リストを持っていて、1番目の棚、2番目の棚…と順に見て回ります。背表紙に「tenki」とある本を最初に見つけた棚で探すのをやめ、その本を持ってきます。

この「本棚のリスト」が `sys.path` です。中身は、フォルダのパス(文字列)が並んだ、ただの Python のリストです。

たとえPython での正体
本の名前import の後ろに書いた名前(tenki)
本棚のリストsys.path(探すフォルダの名簿)
本tenki.py などのファイル
一度持ってきた本を置いておく机sys.modules(読み込み済みの棚。後で出てきます)

ここで大事なのは、名簿に載っていないフォルダは、どんなに近くにあっても見ないということです。JS(Node.js)では、require("lodash") と書くと、書いたファイルのフォルダから親フォルダへ node_modules を順に遡って探します。Python はそういう「近くを探す」ことをしません。探す場所は名簿がすべてです。

この違いを頭に置いておくと、この先の「なぜ見つからない?」がほとんど説明できるようになります。

  • JS から来た人の Python 08 ― import の正体
  • 2 / 30
  • 一言でいうと:決まった順に棚を見て回る係
  • 名簿(sys.path)
  • 0 プロジェクトのフォルダ
  • 検索
  • import tenki
  • 探すのは名前だけ
  • 1 標準ライブラリ(zip)
  • OK
  • 2 標準ライブラリ
  • 上から順に のぞく
  • 最初の1つ
  • 3 C 拡張の置き場
  • 4 site-packages
  • たとえるなら、決まった順番に本棚を見て回る図書係。「tenki」という背表紙を最初に見つけた棚で探すのをやめる
  • 名簿に無いフォルダは、どれだけ近くにあっても見ない(ここが JS の node_modules と違うところ)
  • ひらめき
  • 名簿(sys.path)に書かれたフォルダを、上から順にのぞいて、最初に見つけたものを使う。

ファイル1つが、モジュール1つ

まず言葉をそろえます。Python では、import できる単位をモジュールと呼びます。いちばん基本の形は、.py ファイル1つがモジュール1つです。

ディスクの上import で書く名前できるモジュール
tenki.pyimport tenkiモジュール tenki
weather_api.pyimport weather_apiモジュール weather_api

名前は、ファイル名から .py を取ったものです。だから import には拡張子もパスも書きません。逆に言うと、ファイル名は Python の名前として使える形にする必要があります。tenki-app.py のようにハイフンを入れると、import tenki-app とは書けません(引き算に見えるため)。

import したモジュールは、名前の入った箱のようなものです。ファイルの中で作った変数や関数が、そのまま箱の中身になります。

python
import tenki
print(tenki.CITY)     # Tokyo
tenki.show(21)        # Tokyo: 21℃

箱には、Python が自動で入れる名前もあります。__name__ はモジュールの名前(ここでは 'tenki')、__file__ は実際に読んだファイルのパスです。dir(tenki) で中身の名前を全部出すと、実物はこうなります。

['CITY', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__',
 '__name__', '__package__', '__spec__', 'show']

自分で書いた CITY と show のほかに、Python が付けた名前が並んでいます。__file__ は、この章で何度も使う「どこから来たか」の手がかりです。

  • JS から来た人の Python 08 ― import の正体
  • 3 / 30
  • ファイル1つが、モジュール1つ
  • 書類
  • tenki.py
  • モジュール tenki(メモリの中)
  • ディスクの上のファイル
  • 名前
  • 中身
  • CITY = "Tokyo"
  • CITY
  • 'Tokyo'
  • import
  • show
  • 関数
  • def show(temp):
  • print(f"{CITY}: {temp}℃")
  • __name__
  • 'tenki'
  • __file__
  • '…/tenki-app/tenki.py'
  • モジュールの名前 = ファイル名から .py を取ったもの。だから import には名前だけを書く
  • ファイルの中で作った変数・関数は、そのままモジュールの「中身」(tenki.CITY、tenki.show)になる
  • ひらめき
  • tenki.py を import すると「tenki」という名前のモジュール(名前の入った箱)ができる。

import tenki の1行で起きる、4つのこと

import tenki の1行で、Python は次の4つを順番に行います。Python の公式ドキュメント(The import system)に書かれている手順を、言葉を簡単にしたものです。

順番やること見つかったら
①`sys.modules`(読み込み済みの棚)に tenki がもう有るか見る②③を飛ばして④へ
②無ければ、`sys.path` の名簿のフォルダを上から順に探すその段で探すのをやめる
③見つけたファイルを上から最後まで実行し、その結果をモジュールにする棚に置く
④import を書いたファイルの中に、tenki という名前を付ける使えるようになる

②で名簿の最後まで見ても無ければ、そこで ModuleNotFoundError になります。

いちばん意外なのは③でしょう。import は、ファイルを「読み込む」だけではなく「実行」します。ファイルの中の print は、import したときに本当に動きます。

もう1つ大事なのは①です。一度 import したモジュールは棚に置かれるので、2回目の import はファイルを探しも実行もせず、棚から取り出すだけです。

実は②の前に、「Python 本体に最初から組み込まれた名前かどうか」も確かめています。sys などがそうです。自分のファイルや pip で入れたライブラリには関係しないので、後で別に見ることにして、まずはこの4つを tenki・json・requests で1段ずつ追いかけます。

  • JS から来た人の Python 08 ― import の正体
  • 4 / 30
  • import tenki の1行で起きる、4つのこと
  • ディスク
  • 検索
  • 再生
  • リンク
  • ① 棚を見る
  • ② 名簿を探す
  • ③ 上から実行
  • ④ 名前を付ける
  • sys.modules に
  • sys.path の
  • ファイルを実行して
  • tenki という名前で
  • もう有る?
  • フォルダを上から
  • モジュールを作る
  • 使えるようにする
  • ①で見つかれば、②③は飛ばして④だけ。だから2回目の import は一瞬で終わり、ファイルも実行されない
  • 正確には②の前に「Python 本体に組み込まれた名前か」も確かめる(sys など。後で出てくる)
  • この章では、この4つを tenki・json・requests の3つで1段ずつ追いかける
  • ひらめき
  • 棚を見る → 無ければ名簿のフォルダを上から探す → 見つけたら上から実行 → 名前を付ける。

名簿の実物:print(sys.path)

名簿 sys.path を実際に出してみます。sys は Python の動いている状態を見せてくれる組み込みのモジュールで、sys.path はただのリストです。

python
# where.py
import sys
for i, p in enumerate(sys.path):
    print(i, p)

tenki-app というフォルダに where.py を置き、仮想環境(第12章)の python で実行すると、こうなります。

$ .venv/bin/python where.py
0 /Users/you/tenki-app
1 /Library/Frameworks/Python.framework/Versions/3.13/lib/python313.zip
2 /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13
3 /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/lib-dynload
4 /Users/you/tenki-app/.venv/lib/python3.13/site-packages

python.org から入れた Python 3.13 の macOS での形です(筆者の環境で実行した結果のパスを、読みやすい macOS の例に置き換えています。並び順とフォルダ名は実物どおりです)。Homebrew や uv で入れた Python なら、1〜3番の前半が別の場所になりますが、並び方は同じです。

公式ドキュメント(The initialization of the sys.path module search path)によると、名簿はこの順で作られます。

番号何のフォルダ誰が入れる
0起動したスクリプトのあるフォルダ(python -c や対話モードなら今いるフォルダ)Python が起動時に
(あれば)環境変数 PYTHONPATH に書いたフォルダあなた
1〜3標準ライブラリと、その C 言語の部品Python が自分の場所から計算
4site-packages(pip で入れたライブラリの置き場)起動時に動く site モジュール
  • JS から来た人の Python 08 ― import の正体
  • 5 / 30
  • 名簿の実物:print(sys.path)
  • # where.py
  • import sys
  • プロジェクト
  • 標準ライブラリ
  • 入れたもの
  • for i, p in enumerate(sys.path):
  • print(i, p)
  • 黄=自分のコード、緑=pip で入れたもの
  • $ .venv/bin/python where.py
  • 0 /Users/you/tenki-app
  • 1 /Library/Frameworks/Python.framework/Versions/3.13/lib/python313.zip
  • 2 /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13
  • 3 /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/lib-dynload
  • 4 /Users/you/tenki-app/.venv/lib/python3.13/site-packages
  • ひらめき
  • sys.path はただのリスト。0番目はスクリプトのあるフォルダ、最後が site-packages。

舞台:パソコンの中のフォルダの木

名簿の5つのフォルダは、ディスクの上のどこにあるのでしょうか。フォルダの木にすると、図のように2か所に分かれています。

左はあなたのプロジェクトです。/Users/you/tenki-app の中に、自分で書いた main.py と tenki.py、そして仮想環境の .venv があります。pip で入れた requests は、.venv/lib/python3.13/site-packages/ の中に requests/ というフォルダとして置かれています。

右は Python を入れた場所です。python.org のインストーラーは /Library/Frameworks/Python.framework/Versions/3.13/ に入れます。

場所中にあるもの
bin/python3.13Python の本体(インタプリタ。第1章)
lib/python3.13/標準ライブラリ。json/・os.py・random.py など、.py ファイルとフォルダがそのまま並んでいる
lib/python3.13/lib-dynload/標準ライブラリのうち、C で書いてコンパイルした部品(.so ファイル)
lib/python313.zip名簿には載っているが、ふつうはファイル自体が無い

注目してほしいのは、標準ライブラリも、あなたの tenki.py と同じ「ディスクの上の .py ファイル」だということです。Finder で開けば中身も読めます。特別な魔法の場所ではありません。

python313.zip は、標準ライブラリを1つの zip にまとめて配る作り方のために名簿へ入っている場所です。Python は zip の中からも import できるのですが、ふつうの環境ではこのファイルは作られていません。無いフォルダやファイルは、探すときに「無かった」として飛ばされるだけで、エラーにはなりません。

  • JS から来た人の Python 08 ― import の正体
  • 6 / 30
  • 舞台:パソコンの中のフォルダの木
  • あなたのプロジェクト
  • Python を入れた場所(python.org 版)
  • フォルダ
  • Users/
  • フォルダ
  • Library/Frameworks/Python.framework/
  • フォルダ
  • you/
  • フォルダ
  • Versions/3.13/
  • フォルダ
  • tenki-app/
  • CPU
  • bin/python3.13(本体)
  • 書類
  • main.py
  • フォルダ
  • lib/
  • 書類
  • tenki.py
  • ファイル
  • python313.zip(無い)
  • フォルダ
  • .venv/lib/python3.13/
  • フォルダ
  • python3.13/
  • フォルダ
  • site-packages/
  • 本
  • json/
  • 荷物
  • requests/
  • 書類
  • os.py random.py …
  • 荷物
  • idna/ certifi/ …
  • フォルダ
  • lib-dynload/
  • 枠で囲んだ5か所が sys.path の名簿に載っているフォルダ。緑の2つがプロジェクト側、残りが Python 側
  • python313.zip は名簿には載っているが、ふつうはファイル自体が無い。無ければ飛ばすだけ
  • ひらめき
  • 名簿の5つのフォルダは、ディスクのあちこちにある。プロジェクトの中と、Python を入れた場所。

木の5か所を、探す順に並べると名簿になる

フォルダの木から、名簿に載っている5か所を取り出して、探す順番に並べ直すと、図の右のようになります。これが sys.path です。

ここから先は、この図を舞台にして import を追いかけます。

図の場所表しているもの
左上の黒い板import を書いた main.py
左下の黄色い棚sys.modules(一度読み込んだモジュールを置いておく棚)
右の5段sys.path の名簿。0段目から順に見る
各段の右端そのフォルダに入っているものの例

名簿のパスは長いので、図では途中を「…」で略しています。実物は前に出した print(sys.path) の出力のとおりです。

main.py の3行を、上から1行ずつ処理します。黒い小包が「いま探している名前」です。小包が棚をのぞき、無ければ名簿の0段目、1段目…と1段ずつ下りていきます。見つかった段は緑の枠と ○、無かった段は灰色と × で示します。

JS から来た人は、ここで「Node の node_modules のように、プロジェクトの中の決まったフォルダを探すのかな」と想像するかもしれません。半分は合っています。4段目の site-packages は、役割としては node_modules に近いものです。違うのは、探す順番が1本の名簿で決まっていて、プロジェクトのフォルダ(0段目)と標準ライブラリが、site-packages より先に来ることです。

  • JS から来た人の Python 08 ― import の正体
  • 7 / 30
  • 木の5か所を、探す順に並べると名簿になる
  • # main.py
  • sys.path[0] スクリプトのあるフォルダ
  • main.py tenki.py
  • import tenki
  • /Users/you/tenki-app
  • import json
  • sys.path[1] 標準ライブラリ(zip)
  • import requests
  • /Library/…/Versions/3.13/lib/python313.zip
  • (ふつうは無い)
  • sys.path[2] 標準ライブラリ
  • sys.modules
  • /Library/…/Versions/3.13/lib/python3.13
  • json/ os.py …
  • 読み込み済みの棚
  • 最初から sys・os など数十個
  • sys.path[3] C 拡張の置き場
  • /Library/…/lib/python3.13/lib-dynload
  • *.so のファイル
  • sys.path[4] site-packages
  • /Users/you/tenki-app/.venv/lib/python3.13/site-packages
  • requests/ idna/ …
  • 左上:import を書いた main.py 左下:sys.modules(一度読んだモジュールを置いておく棚)
  • 右:sys.path の名簿。図では途中のフォルダ名を「…」で略している
  • ひらめき
  • import はこの名簿を上から下へ。以降の図は、左の main.py と棚、右の名簿で追いかける。

import tenki ①:まず棚(sys.modules)を見る

main.py の1行目、import tenki から始めます。

最初に見るのは名簿ではなく、棚です。sys.modules は「モジュールの名前 → モジュール本体」の辞書(JS のオブジェクトや Map にあたるもの。第4章)で、それまでに import したモジュールが全部入っています。

python
import sys
print(len(sys.modules))       # 35(この環境の場合)
print("tenki" in sys.modules)  # False
print("os" in sys.modules)     # True

プログラムを始めたばかりなのに、棚はもう空ではありません。Python は起動するときに、自分が動くために必要な sys や os などを先に import しているからです。数は環境によって違いますが、数十個あります。

でも、tenki はまだありません。当然です。一度も import していないのですから。

棚に…次にすること
あるそれをそのまま使う(②③を飛ばして④へ)
無い②名簿を上から探す

tenki は無かったので、小包は名簿の0段目へ向かいます。

  • JS から来た人の Python 08 ― import の正体
  • 8 / 30
  • import tenki ①:まず棚(sys.modules)を見る
  • # main.py
  • sys.path[0] スクリプトのあるフォルダ
  • main.py tenki.py
  • import tenki
  • /Users/you/tenki-app
  • import json
  • sys.path[1] 標準ライブラリ(zip)
  • import requests
  • /Library/…/Versions/3.13/lib/python313.zip
  • (ふつうは無い)
  • sys.path[2] 標準ライブラリ
  • sys.modules
  • /Library/…/Versions/3.13/lib/python3.13
  • json/ os.py …
  • 読み込み済みの棚
  • 最初から sys・os など数十個
  • sys.path[3] C 拡張の置き場
  • /Library/…/lib/python3.13/lib-dynload
  • *.so のファイル
  • sys.path[4] site-packages
  • tenki を探す
  • /Users/you/tenki-app/.venv/lib/python3.13/site-packages
  • requests/ idna/ …
  • sys.modules は「名前 → モジュール」の辞書。起動した時点で sys や os など数十個が入っている
  • tenki はまだ無い → ②へ
  • ひらめき
  • 棚に「tenki」は無い。まだ一度も読んでいないので、名簿を探しに行く。

import tenki ②:名簿の0段目で見つかる

名簿の0段目は、起動したスクリプトのあるフォルダ、つまり /Users/you/tenki-app です。python3 main.py と起動したので、main.py のあるフォルダが0段目になっています。

そこに tenki.py があるので、見つかりました。探すのはここで終わりです。

各段で Python が確かめているのは、おおまかに次のものです。

見つけるもの例詳しくは
tenki/ というフォルダ(中に __init__.py)パッケージ第9章
tenki.pyふつうのモジュールこの章
tenki.cpython-313-darwin.so などC で書いた部品3段目の話

大事なのは、最初に見つかった段で探すのをやめることです。仮に4段目の site-packages にも tenki という名前のライブラリが入っていたとしても、0段目で先に見つかった自分の tenki.py が使われます。この性質は、後で見る「自分のファイル名が本物を隠す事故」の原因にもなります。

JS なら require("./tenki") のように、自分のファイルは ./ で始まる相対パスで書くのが決まりでした。Python では自分のファイルも import tenki と名前だけで書けます。それは、スクリプトのあるフォルダがたまたま名簿の0段目に入っているからです。

  • JS から来た人の Python 08 ― import の正体
  • 9 / 30
  • import tenki ②:名簿の0段目で見つかる
  • # main.py
  • sys.path[0] スクリプトのあるフォルダ
  • OK
  • main.py tenki.py
  • import tenki
  • /Users/you/tenki-app
  • tenki を探す
  • import json
  • sys.path[1] 標準ライブラリ(zip)
  • import requests
  • /Library/…/Versions/3.13/lib/python313.zip
  • (ふつうは無い)
  • sys.path[2] 標準ライブラリ
  • sys.modules
  • /Library/…/Versions/3.13/lib/python3.13
  • json/ os.py …
  • 読み込み済みの棚
  • 最初から sys・os など数十個
  • sys.path[3] C 拡張の置き場
  • /Library/…/lib/python3.13/lib-dynload
  • *.so のファイル
  • sys.path[4] site-packages
  • /Users/you/tenki-app/.venv/lib/python3.13/site-packages
  • requests/ idna/ …
  • 各段で見るのは「tenki/ というフォルダ(パッケージ・第9章)」か「tenki.py などのファイル」があるか
  • 見つかったら、下の段はもう見ない。1段目以降に tenki があっても使われない
  • ひらめき
  • sys.path[0] はスクリプトのあるフォルダ。そこに tenki.py がある。探すのはここで終わり。

import tenki ③:tenki.py を上から実行して、中身を作る

見つけた tenki.py を、Python は上から最後まで実行します。ここが JS の人にとっていちばん意外なところかもしれません。確かめるために、tenki.py の最初と最後に print を仕込んでおきます。

python
# tenki.py
print("tenki.py を実行中… __name__ =", __name__)

CITY = "Tokyo"

def show(temp):
    print(f"{CITY}: {temp}℃")

print("tenki.py の最後まで来た")

main.py で import tenki するだけで、この2つの print が本当に表示されます。

$ python3 main.py
tenki.py を実行中… __name__ = tenki
tenki.py の最後まで来た

CITY = "Tokyo" も def show も、実行される「文」です。def は「関数を作って show という名前を付ける」という命令なので、実行が通り過ぎたときに初めて関数ができます。こうして最後まで実行し終わったときに残っていた名前(CITY・show)が、モジュール tenki の中身になります。

もう1つ、公式ドキュメントに書かれている細かい順番があります。モジュールは、実行を始める前に棚(sys.modules)に置かれます。図で棚に tenki の札が先に入っているのはそのためです。こうしておくと、tenki.py の中から巡り巡って tenki を import し直しても、無限に繰り返さずに済みます。

なお、実行のついでに __pycache__/tenki.cpython-313.pyc というファイルができます。第1章で見たバイトコードの控えで、次からの読み込みを速くするためのものです。

  • JS から来た人の Python 08 ― import の正体
  • 10 / 30
  • import tenki ③:tenki.py を上から実行して、中身を作る
  • # main.py
  • # tenki.py
  • モジュール tenki
  • import tenki
  • print("tenki.py を実行中… __name__ =", __name__)
  • import json
  • CITY = "Tokyo"
  • CITY = 'Tokyo'
  • import requests
  • def show(temp):
  • show = 関数
  • print(f"{CITY}: {temp}℃")
  • __name__ = 'tenki'
  • print("tenki.py の最後まで来た")
  • __file__ = '…/tenki.py'
  • sys.modules
  • 読み込み済みの棚
  • $ python3 main.py
  • 最初から sys・os など数十個
  • tenki.py を実行中… __name__ = tenki
  • tenki
  • tenki.py の最後まで来た
  • tenki を探す
  • def も「関数を作って名前を付ける」という実行される文。最後まで実行して残った名前が中身になる
  • モジュールは実行を始める前に棚に置かれる(自分を import し直しても無限に繰り返さないため)
  • ひらめき
  • 見つけたファイルは「読み込む」のではなく「実行する」。print も上から順に動く。

import tenki ④:main.py に「tenki」という名前を付ける

最後に、import tenki を書いた main.py の中に、`tenki` という名前を作り、できたモジュールを指すようにします。これで tenki.show(21) と書けるようになります。

第4章で「名前は札で、オブジェクトに付ける」と見ました。import も同じです。main.py の名前の表に tenki という札が増え、その札はメモリの中のモジュールに付いています。棚(sys.modules)の "tenki" も、同じモジュールに付いています。

python
import sys
import tenki
print(sys.modules["tenki"] is tenki)   # True

is は「同じ1つのオブジェクトか」を確かめる比較でした(第3章)。True なので、棚にあるものと、main.py の tenki は、コピーではなく同じ1つです。

ここまでの4段をまとめます。

段tenki の場合
① 棚を見る無い
② 名簿を探す0段目(/Users/you/tenki-app)で tenki.py が見つかる
③ 上から実行print が2回動き、CITY と show ができる。棚に置かれる
④ 名前を付けるmain.py に tenki ができる

次は2行目、import json です。今度は0段目では見つかりません。

  • JS から来た人の Python 08 ― import の正体
  • 11 / 30
  • import tenki ④:main.py に「tenki」という名前を付ける
  • # main.py
  • モジュール tenki
  • import tenki
  • main.py の名前の表
  • import json
  • CITY = 'Tokyo'
  • tenki
  • show = 関数
  • import requests
  • 指す
  • __name__ = 'tenki'
  • __file__ = '…/tenki.py'
  • sys.modules
  • 読み込み済みの棚
  • 最初から sys・os など数十個
  • 棚も同じものを指す
  • tenki
  • print(sys.modules["tenki"] is tenki) # True(同じ1つのもの)
  • ひらめき
  • main.py の中に tenki という名前ができ、棚にあるのと同じモジュールを指す。

import json ①:棚には無い

2行目の import json に進みます。json は、JSON 文字列と Python の辞書・リストを相互に変換する標準ライブラリです。JS の JSON.parse / JSON.stringify にあたるものが、Python では import しないと使えません。

標準ライブラリなら最初から読み込まれていそうですが、実際に確かめると違います。

python
import sys
print("json" in sys.modules)   # False

Python は、起動に必要な最低限のものしか先に import しません。json は、あなたが import したときに初めて探されます。棚にあるのは、今のところ起動時の数十個と、1行目で入った tenki だけです。

JS では JSON は最初からあるグローバルなオブジェクトでした。Python では、標準ライブラリの大部分は「Python と一緒にディスクに置いてあるが、import するまで使えない部品」です。最初から使える print や len などは組み込み関数と呼ばれ、import は要りません。

JSPython
JSON の変換JSON(最初からある)import json が必要
画面に出すconsole.log(最初からある)print(最初からある)
ファイル操作import fs from "node:fs"import pathlib など

では、名簿を上から探します。

  • JS から来た人の Python 08 ― import の正体
  • 12 / 30
  • import json ①:棚には無い
  • # main.py
  • sys.path[0] スクリプトのあるフォルダ
  • main.py tenki.py
  • import tenki
  • /Users/you/tenki-app
  • import json
  • sys.path[1] 標準ライブラリ(zip)
  • import requests
  • /Library/…/Versions/3.13/lib/python313.zip
  • (ふつうは無い)
  • sys.path[2] 標準ライブラリ
  • sys.modules
  • /Library/…/Versions/3.13/lib/python3.13
  • json/ os.py …
  • 読み込み済みの棚
  • 最初から sys・os など数十個
  • sys.path[3] C 拡張の置き場
  • /Library/…/lib/python3.13/lib-dynload
  • *.so のファイル
  • tenki
  • sys.path[4] site-packages
  • json を探す
  • /Users/you/tenki-app/.venv/lib/python3.13/site-packages
  • requests/ idna/ …
  • 起動直後の sys.modules に "json" は無い(この環境で試すと False)
  • → 名簿を上から探す。0段目から順番に
  • ひらめき
  • json は Python に付いてくる標準ライブラリだが、起動しただけでは棚に入っていない。

import json ②:0段目(プロジェクト)には無い

小包は0段目、/Users/you/tenki-app をのぞきます。ここにあるのは main.py と tenki.py と .venv だけです。json.py も json/ フォルダも無いので、×を付けて次の段へ進みます。

ここで一度立ち止まって、もし0段目に json.py があったらを考えてみてください。たとえば練習のつもりで、JSON を試すファイルに json.py という名前を付けていたらどうなるでしょう。

名簿は上から見て、最初に見つけた段で探すのをやめるのでした。0段目の自作 json.py が先に見つかり、2段目にある本物の json には永久に届きません。json.dumps を呼ぶと、「そんなものは無い」というエラーになります。

0段目に…import json で使われるもの
何も無い本物(標準ライブラリの json)
自作の json.py がある自作の json.py(本物は隠れる)

これは Python を始めたばかりの人がほぼ必ず一度は踏む事故です。実物のエラーは後の「よくある事故」で見ます。対策は簡単で、標準ライブラリや、入れたライブラリと同じ名前のファイルを作らないことです(random.py・email.py・test.py なども要注意です)。

  • JS から来た人の Python 08 ― import の正体
  • 13 / 30
  • import json ②:0段目(プロジェクト)には無い
  • # main.py
  • sys.path[0] スクリプトのあるフォルダ
  • NG
  • json を探す
  • main.py tenki.py
  • import tenki
  • /Users/you/tenki-app
  • import json
  • sys.path[1] 標準ライブラリ(zip)
  • import requests
  • /Library/…/Versions/3.13/lib/python313.zip
  • (ふつうは無い)
  • sys.path[2] 標準ライブラリ
  • sys.modules
  • /Library/…/Versions/3.13/lib/python3.13
  • json/ os.py …
  • 読み込み済みの棚
  • 最初から sys・os など数十個
  • sys.path[3] C 拡張の置き場
  • /Library/…/lib/python3.13/lib-dynload
  • *.so のファイル
  • tenki
  • sys.path[4] site-packages
  • /Users/you/tenki-app/.venv/lib/python3.13/site-packages
  • requests/ idna/ …
  • ★もしここに自分で json.py を作っていたら、標準の json ではなく「そちら」が見つかってしまう
  • 0段目がいちばん先に見られるから。よくある事故で、後の「よくある間違い」で実物を見る
  • ひらめき
  • tenki-app の中に json.py も json/ も無い。次の段へ。

import json ③:1段目(zip)はファイル自体が無い

1段目は /Library/Frameworks/Python.framework/Versions/3.13/lib/python313.zip です。

名前のとおり zip ファイルを指しています。Python は、zip ファイルの中に入った .py を、フォルダの中にあるのと同じように import できます。標準ライブラリを1つの zip にまとめて持ち運べるように、名簿にこの場所が用意されています。

ところが、python.org 版をはじめ、ふつうに入れた Python にはこのファイルがありません。実際、筆者の環境でも ls すると「No such file or directory」でした。名簿に載っているのに、実物が無いのです。

それでも問題はありません。名簿の段は「探しに行く候補」にすぎず、その場所が無ければ何も見つからなかったのと同じ扱いで、黙って次の段へ進みます。

1段目の状態起きること
zip が無い(ふつう)何もせず次の段へ
zip があり、中に json があるそこから import する

この「名簿には載っているが、実在しなくてもよい」という性質は、自分で PYTHONPATH を設定したときにも同じです。打ち間違えたフォルダを入れても、エラーは出ず、ただ見つからないだけです。「なぜか import できない」ときに気づきにくい原因の1つなので覚えておきましょう。

  • JS から来た人の Python 08 ― import の正体
  • 14 / 30
  • import json ③:1段目(zip)はファイル自体が無い
  • # main.py
  • sys.path[0] スクリプトのあるフォルダ
  • NG
  • main.py tenki.py
  • import tenki
  • /Users/you/tenki-app
  • import json
  • sys.path[1] 標準ライブラリ(zip)
  • import requests
  • /Library/…/Versions/3.13/lib/python313.zip
  • NG
  • json を探す
  • (ふつうは無い)
  • sys.path[2] 標準ライブラリ
  • sys.modules
  • /Library/…/Versions/3.13/lib/python3.13
  • json/ os.py …
  • 読み込み済みの棚
  • 最初から sys・os など数十個
  • sys.path[3] C 拡張の置き場
  • /Library/…/lib/python3.13/lib-dynload
  • *.so のファイル
  • tenki
  • sys.path[4] site-packages
  • /Users/you/tenki-app/.venv/lib/python3.13/site-packages
  • requests/ idna/ …
  • 標準ライブラリを1つの zip にまとめて配る作り方のための場所。python.org 版やふつうの環境では使われていない
  • 無い場所は「無かった」として飛ばすだけで、エラーにはならない
  • ひらめき
  • python313.zip は名簿に載っているだけ。存在しないので、何もせず次の段へ。

import json ④:2段目(標準ライブラリ)に json/ がある

2段目は /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13、標準ライブラリの本体です。ここに json/ というフォルダがあり、見つかりました。

json は1つのファイルではなくフォルダです。中を ls すると、実物はこうなっています。

$ ls /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/json/
__init__.py  __pycache__  decoder.py  encoder.py  scanner.py  tool.py

このように、__init__.py を持ったフォルダをパッケージと呼びます(第9章でくわしく扱います)。フォルダを import すると、中の __init__.py が上から実行され、それがモジュール json の中身になります。json.dumps や json.loads は、この __init__.py の中で定義されています。

python
>>> import json
>>> json.__file__
'/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/json/__init__.py'

見つかったので、3段目・4段目は見ません。json が棚に入り、main.py に json という名前が付きます。

エディタで json/__init__.py を開いてみてください。先頭には説明の文章があり、その後に from .decoder import JSONDecoder のような、見慣れた Python のコードが続きます。標準ライブラリは、誰かが書いた普通の Python ファイルです。あなたの tenki.py と作りは変わりません。

  • JS から来た人の Python 08 ― import の正体
  • 15 / 30
  • import json ④:2段目(標準ライブラリ)に json/ がある
  • # main.py
  • sys.path[0] スクリプトのあるフォルダ
  • NG
  • main.py tenki.py
  • import tenki
  • /Users/you/tenki-app
  • import json
  • sys.path[1] 標準ライブラリ(zip)
  • import requests
  • /Library/…/Versions/3.13/lib/python313.zip
  • NG
  • (ふつうは無い)
  • sys.path[2] 標準ライブラリ
  • sys.modules
  • /Library/…/Versions/3.13/lib/python3.13
  • OK
  • json を探す
  • json/ os.py …
  • 読み込み済みの棚
  • 最初から sys・os など数十個
  • sys.path[3] C 拡張の置き場
  • /Library/…/lib/python3.13/lib-dynload
  • *.so のファイル
  • tenki
  • json
  • sys.path[4] site-packages
  • /Users/you/tenki-app/.venv/lib/python3.13/site-packages
  • requests/ idna/ …
  • json.__file__ は …/lib/python3.13/json/__init__.py。json は1ファイルではなくフォルダ(パッケージ・第9章)
  • 3段目・4段目は見ない。標準ライブラリも、あなたのファイルと同じ「ただの .py」
  • ひらめき
  • 見つかったのは json というフォルダ。中の __init__.py が実行されて、モジュール json になる。

import requests ①:棚には無い

3行目、import requests です。requests は、インターネットの Web API に HTTP でリクエストを送るためのライブラリで、tenki が天気を取ってくるのに使います(JS の fetch や axios にあたります)。

requests は Python に付いてきません。世界中の誰でもパッケージを置ける PyPI(パイピーアイ、pypi.org)に公開されていて、pip install requests と打つと、ダウンロードされてディスクに置かれます(第11章)。置かれる先が、仮想環境 .venv の中の site-packages です(第12章)。

つまり、import requests の時点でネットにつながる必要はありません。ダウンロードは pip install のときに一度だけ済んでいて、import はディスクの上を探すだけです。

動作いつネット
pip install requests最初に一度だけ使う(PyPI から取ってくる)
import requestsプログラムを動かすたび使わない(ディスクを探すだけ)

棚には、tenki と json はありますが、requests はまだありません。小包は、名簿の0段目から探し始めます。

  • JS から来た人の Python 08 ― import の正体
  • 16 / 30
  • import requests ①:棚には無い
  • # main.py
  • sys.path[0] スクリプトのあるフォルダ
  • main.py tenki.py
  • import tenki
  • /Users/you/tenki-app
  • import json
  • sys.path[1] 標準ライブラリ(zip)
  • import requests
  • /Library/…/Versions/3.13/lib/python313.zip
  • (ふつうは無い)
  • sys.path[2] 標準ライブラリ
  • sys.modules
  • /Library/…/Versions/3.13/lib/python3.13
  • json/ os.py …
  • 読み込み済みの棚
  • 最初から sys・os など数十個
  • sys.path[3] C 拡張の置き場
  • /Library/…/lib/python3.13/lib-dynload
  • *.so のファイル
  • tenki
  • json
  • sys.path[4] site-packages
  • requests を探す
  • /Users/you/tenki-app/.venv/lib/python3.13/site-packages
  • requests/ idna/ …
  • requests は Python に付いてこない。誰かが書いて PyPI に置いたライブラリを、pip で入れたもの(第11章)
  • 入れた先は .venv の site-packages(仮想環境・第12章)
  • ひらめき
  • tenki と json は棚にあるが、requests はまだ。同じ手順で名簿を探す。

import requests ②:0〜2段目には無い

0段目のプロジェクトのフォルダにも、1段目の(存在しない)zip にも、2段目の標準ライブラリにも、requests はありません。3つの段に×が付きました。

2段目の標準ライブラリには、数百のモジュールが入っています(一覧は sys.stdlib_module_names で見られます)。インターネットにアクセスするための urllib もその1つで、実は requests が無くても HTTP のリクエストは送れます。

選択肢置き場所使い心地
urllib.request標準ライブラリ(2段目)入れなくて使えるが、書くことが多い
requestssite-packages(4段目)入れる必要があるが、短く書ける

多くの人が requests を入れて使うのは、書きやすいからです。「標準ライブラリで足りるか」「入れる価値があるか」は、ライブラリを選ぶときにいつも考えることです(第10章)。

さて、残りは3段目と4段目です。

  • JS から来た人の Python 08 ― import の正体
  • 17 / 30
  • import requests ②:0〜2段目には無い
  • # main.py
  • sys.path[0] スクリプトのあるフォルダ
  • NG
  • main.py tenki.py
  • import tenki
  • /Users/you/tenki-app
  • import json
  • sys.path[1] 標準ライブラリ(zip)
  • import requests
  • /Library/…/Versions/3.13/lib/python313.zip
  • NG
  • (ふつうは無い)
  • sys.path[2] 標準ライブラリ
  • sys.modules
  • /Library/…/Versions/3.13/lib/python3.13
  • NG
  • requests を探す
  • json/ os.py …
  • 読み込み済みの棚
  • 最初から sys・os など数十個
  • sys.path[3] C 拡張の置き場
  • /Library/…/lib/python3.13/lib-dynload
  • *.so のファイル
  • tenki
  • json
  • sys.path[4] site-packages
  • /Users/you/tenki-app/.venv/lib/python3.13/site-packages
  • requests/ idna/ …
  • 標準ライブラリ(…/lib/python3.13)には json・os・pathlib・urllib など数多くのモジュールがあるが、requests は無い
  • → 次の段へ
  • ひらめき
  • プロジェクトにも、zip にも、標準ライブラリにも requests は無い。

import requests ③:3段目(C 拡張の置き場)にも無い

3段目は …/lib/python3.13/lib-dynload です。ここには、標準ライブラリのうち C 言語で書いてコンパイルした部品が、.so という拡張子のファイルとして置かれています(macOS なら _json.cpython-313-darwin.so のような名前です)。

C で書いた部品を拡張モジュールと呼びます。速さが必要な部分を C で書き、Python からは .py のモジュールとまったく同じように import できます。json の中身も、速くしたい部分はこうした C の部品を使っています。

拡張子中身import の書き方
.pyPython のソースimport 名前
.so(Windows は .pyd)コンパイル済みの C の部品import 名前(同じ)

pip で入れるライブラリにも、C やその他の言語で書かれた拡張モジュールを含むものがあります(numpy など)。そういうライブラリは、OS や CPU ごとに別のファイルが配られます。第11章の wheel の話でまた出てきます。

requests はここにもありません。残るは最後の段だけです。

  • JS から来た人の Python 08 ― import の正体
  • 18 / 30
  • import requests ③:3段目(C 拡張の置き場)にも無い
  • # main.py
  • sys.path[0] スクリプトのあるフォルダ
  • NG
  • main.py tenki.py
  • import tenki
  • /Users/you/tenki-app
  • import json
  • sys.path[1] 標準ライブラリ(zip)
  • import requests
  • /Library/…/Versions/3.13/lib/python313.zip
  • NG
  • (ふつうは無い)
  • sys.path[2] 標準ライブラリ
  • sys.modules
  • /Library/…/Versions/3.13/lib/python3.13
  • NG
  • json/ os.py …
  • 読み込み済みの棚
  • 最初から sys・os など数十個
  • sys.path[3] C 拡張の置き場
  • /Library/…/lib/python3.13/lib-dynload
  • NG
  • requests を探す
  • *.so のファイル
  • tenki
  • json
  • sys.path[4] site-packages
  • /Users/you/tenki-app/.venv/lib/python3.13/site-packages
  • requests/ idna/ …
  • .so は C で書いてコンパイルした部品。Python からは .py と同じように import できる
  • 残るは最後の段、site-packages だけ
  • ひらめき
  • lib-dynload は標準ライブラリのうち C で書かれた部品(.so)の置き場。ここにも無い。

import requests ④:最後の site-packages で見つかる

4段目、/Users/you/tenki-app/.venv/lib/python3.13/site-packages に、requests/ というフォルダがありました。pip install が置いていったものです。

$ ls .venv/lib/python3.13/site-packages/
certifi/   certifi-2026.7.22.dist-info/   charset_normalizer/ …
idna/      idna-3.20.dist-info/           pip/  pip-25.3.dist-info/
requests/  requests-2.34.2.dist-info/     urllib3/  urllib3-2.8.0.dist-info/

requests も json と同じく、__init__.py を持つフォルダ(パッケージ)です。見つかると、requests/__init__.py が上から実行されます。その中にも import urllib3 などが書かれていて、それぞれが同じ4つの手順で探され、棚に入っていきます。requests の横に urllib3 や idna が並んでいるのは、requests が使う部品として pip が一緒に入れたからです。筆者の環境では、import requests の1行で棚が 59 個から 304 個に増えました。

「pip install した」とは、「名簿の最後の段のフォルダに、ライブラリのフォルダを置いた」ということです。だから import で見つかります。逆に、名簿の最後まで探して無ければ、

ModuleNotFoundError: No module named 'requests'

になります。これが「入れたはずなのに無いと言われる」エラーの正体で、多くは「別の python の site-packages に入れた」ことが原因です(第12章)。

  • JS から来た人の Python 08 ― import の正体
  • 19 / 30
  • import requests ④:最後の site-packages で見つかる
  • # main.py
  • sys.path[0] スクリプトのあるフォルダ
  • import tenki
  • /Users/you/tenki-app
  • NG
  • main.py tenki.py
  • import json
  • sys.path[1] 標準ライブラリ(zip)
  • import requests
  • /Library/…/Versions/3.13/lib/python313.zip
  • NG
  • (ふつうは無い)
  • sys.path[2] 標準ライブラリ
  • sys.modules
  • /Library/…/Versions/3.13/lib/python3.13
  • NG
  • json/ os.py …
  • 読み込み済みの棚
  • 最初から sys・os など数十個
  • sys.path[3] C 拡張の置き場
  • /Library/…/lib/python3.13/lib-dynload
  • NG
  • *.so のファイル
  • tenki
  • json
  • sys.path[4] site-packages
  • OK
  • requests
  • /Users/you/tenki-app/.venv/lib/python3.13/site-packages
  • requests を探す
  • requests/ idna/ …
  • pip install は「site-packages にフォルダを置く」こと。置いたから、名簿の最後の段で見つかる
  • requests の中にも import urllib3 などがあり、同じ手順で次々に棚へ入る(この環境では 59 → 304 個)
  • ひらめき
  • pip が置いた requests/ フォルダがここにある。名簿の最後まで無ければ ModuleNotFoundError。

どこから来たかは、__file__ を見ればわかる

ここまでの結果を、実物で確かめます。対話モード(第1章の REPL)で3つを import し、__file__ を出します。

$ .venv/bin/python
>>> import tenki, json, requests
>>> tenki.__file__
'/Users/you/tenki-app/tenki.py'
>>> json.__file__
'/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/json/__init__.py'
>>> requests
<module 'requests' from '/Users/you/tenki-app/.venv/lib/python3.13/site-packages/requests/__init__.py'>

モジュールをそのまま表示しても、from '…' の後ろにパスが出ます。

モジュール見つかった段ファイル
tenki0(プロジェクト)tenki-app/tenki.py
json2(標準ライブラリ)…/python3.13/json/__init__.py
requests4(site-packages)…/site-packages/requests/__init__.py

「思っていたのと違うものが動いている」と感じたら、まず __file__ を見てください。自作の json.py に隠されていないか、別の仮想環境のライブラリを使っていないか、パスを見れば一発でわかります。

見つかる場所を、実行せずに調べる方法もあります。importlib.util.find_spec("requests").origin は、import するとしたらどのファイルになるかを返します。ファイルを実行しないので、上から実行されては困るモジュールを調べるときに便利です。

  • JS から来た人の Python 08 ― import の正体
  • 20 / 30
  • どこから来たかは、__file__ を見ればわかる
  • $ .venv/bin/python
  • >>> import tenki, json, requests
  • >>> tenki.__file__
  • '/Users/you/tenki-app/tenki.py'
  • >>> json.__file__
  • '/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/json/__init__.py'
  • >>> requests
  • <module 'requests' from '/Users/you/tenki-app/.venv/lib/python3.13/site-packages/requests/__init__.py'>
  • tenki → sys.path[0]
  • json → sys.path[2]
  • requests → sys.path[4]
  • 「思っていたのと違うものが動いている」ときは、まずこれを見る。どの python・どの venv かもパスでわかる
  • ひらめき
  • モジュールを print するか __file__ を見れば、実際に使われたファイルのパスが出る。

sys にはファイルが無い:Python 本体に組み込まれたもの

sys.__file__ を見ようとすると、エラーになります。

>>> import sys
>>> sys
<module 'sys' (built-in)>
>>> sys.__file__
AttributeError: module 'sys' has no attribute '__file__'

(built-in) は組み込みという意味です。sys は、.py ファイルとしてディスクに置かれているのではなく、Python の実行ファイル(bin/python3.13)の中に最初から入っています。Python が動くために欠かせないものなので、別のファイルにしていないのです。

実は、import でモジュールを探す係は3人いて、この順に聞いて回ります(公式ドキュメントでは sys.meta_path の3つの finder)。

順番係見つけるもの
1組み込み実行ファイルの中の sys など
2凍結(frozen)起動を速くするため、実行ファイルに焼き込んだもの
3名簿(sys.path)ここまで追いかけたフォルダの中のファイル

「import tenki の4つのこと」で、②の前に組み込みを確かめると書いたのはこのことです。どれが組み込みかは Python の作り方によって少し違い、sys.builtin_module_names で一覧を見られます。

あなたが書いたファイルや pip で入れたライブラリは、必ず3番目の名簿で見つかります。ふだんは「名簿を上から」だけを覚えておけば困りません。

  • JS から来た人の Python 08 ― import の正体
  • 21 / 30
  • sys にはファイルが無い:Python 本体に組み込まれたもの
  • >>> import sys
  • ① 組み込み(built-in)
  • >>> sys
  • CPU
  • <module 'sys' (built-in)>
  • python の実行ファイルの中。sys など
  • >>> sys.__file__
  • AttributeError: module 'sys' has no
  • 電気
  • ② 凍結(frozen)
  • attribute '__file__'
  • 起動を速くするため中に焼き込んだもの
  • 検索
  • ③ sys.path の名簿
  • ここまでの図で追いかけたもの
  • 探す係は実は3人いて、この順に聞いて回る(sys.meta_path)。自分のファイルや pip のライブラリは必ず③で見つかる
  • 組み込みの顔ぶれは環境で少し違う。気になれば sys.builtin_module_names で見られる
  • ひらめき
  • sys などは実行ファイルの中に最初から入っている。名簿より先に確かめられる。

2回 import しても、実行は1回だけ

import tenki を2回書いたら、tenki.py は2回実行されるでしょうか。確かめます。

python
# main.py
import sys
import tenki
import tenki      # 2回目
tenki.show(21)
print(sys.modules["tenki"] is tenki)
$ python3 main.py
tenki.py を実行中… __name__ = tenki
tenki.py の最後まで来た
Tokyo: 21℃
True

print は1回ずつしか出ていません。2回目の import は、①で棚に tenki があるのを見つけ、②③を飛ばして④の名前付けだけをしたからです。

これは、別のファイルから import した場合も同じです。main.py と weather.py の両方が import tenki と書いても、tenki.py の実行は最初の1回だけで、両方とも棚にある同じ1つのモジュールを受け取ります。そのため、片方で tenki.CITY = "Osaka" と書き換えると、もう片方からもそう見えます。

状況起きること
同じファイルで2回 import2回目は棚から取るだけ
別のファイルから import同じ1つを共有する
ファイルを書き換えた後、同じ Python で import し直す棚の古いものが返る(反映されない)

最後の行は、対話モードや Jupyter で「ファイルを直したのに変わらない」ときの原因です。importlib.reload(tenki) という手もありますが、いちばん確実なのは Python を起動し直すことです。

JS の Node でも、require は2回目からキャッシュ(require.cache)を返し、ESM も1回しか評価しません。「1回だけ実行して使い回す」という考え方は同じです。

  • JS から来た人の Python 08 ― import の正体
  • 22 / 30
  • 2回 import しても、実行は1回だけ
  • # main.py
  • import sys
  • 人々
  • 別のファイルが import しても同じ
  • import tenki
  • main.py も weather.py も import tenki と書けば、
  • import tenki # 2回目
  • どちらも棚の同じ1つを受け取る。片方で
  • tenki.show(21)
  • tenki.CITY を変えると、もう片方にも見える
  • print(sys.modules["tenki"] is tenki)
  • 更新
  • ファイルを直したのに反映されない?
  • $ python3 main.py
  • 動いている途中の Python(REPL など)では
  • tenki.py を実行中… __name__ = tenki
  • 棚が残ったまま。いちばん確実なのは
  • tenki.py の最後まで来た
  • python を起動し直すこと
  • Tokyo: 21℃
  • True
  • ひらめき
  • 2回目は①の棚で見つかって終わり。ファイルは読み直さない。だから print も1回。

from … import と as:違うのは「付ける名前」だけ

import にはいくつかの書き方があります。表のように、違うのは④で main.py に付ける名前だけで、①〜③(棚を見る・名簿を探す・上から実行)はまったく同じです。

書き方main.py で使う使い方の例
import tenkitenkitenki.show(21)
import tenki as ttt.show(21)
from tenki import showshowshow(21)
from tenki import show as sss(21)

実際に from tenki import show を試しても、tenki.py の print は出ます。

$ python3 -c "from tenki import show; show(18)"
tenki.py を実行中… __name__ = tenki
Tokyo: 18℃

つまり、「必要な関数だけを読むから速くなる」ということはありません。ファイルは必ず最後まで実行され、棚には tenki 全体が入ります。main.py に付く名前が show だけになる、というだけの違いです。

JS の書き方と並べるとこうなります。

JS(ESM)Python
import * as tenki from "./tenki.js"import tenki
import { show } from "./tenki.js"from tenki import show
import { show as s } from "./tenki.js"from tenki import show as s

from tenki import *(中の名前をほぼ全部持ってくる)は、どの名前がどこから来たか追えなくなるので、ふつうは使いません。as は、import numpy as np のように長い名前を短くする慣習でよく見かけます。

  • JS から来た人の Python 08 ― import の正体
  • 23 / 30
  • from … import と as:違うのは「付ける名前」だけ
  • 書き方
  • main.py にできる名前
  • 棚(sys.modules)
  • import tenki
  • tenki
  • tenki(丸ごと実行)
  • import tenki as t
  • t(tenki は無い)
  • tenki(同じ)
  • from tenki import show
  • show(tenki は無い)
  • tenki(同じ。丸ごと実行)
  • from tenki import show as s
  • s
  • tenki(同じ)
  • from tenki import *
  • tenki の中の名前ほぼ全部
  • 使わない。どこから来た名前か追えなくなる
  • 「必要な関数だけ読むから速い」ということはない。ファイルは必ず上から最後まで実行される
  • as は長い名前を短くする慣習でよく使う(import numpy as np、import pandas as pd)
  • ひらめき
  • from tenki import show でも tenki.py は丸ごと実行される。④で付ける名前が変わるだけ。

if __name__ == "__main__": の意味

Python のコードでよく見かける、あの1行の意味もここでわかります。

モジュールには __name__ という名前が自動で入るのでした。その値は、どうやって実行されたかで変わります。

実行のしかたtenki.py の中の __name__
python3 tenki.py(直接実行)"__main__"
python3 -m tenki(名前で直接実行)"__main__"
別のファイルから import tenki"tenki"

実際に試した結果です。

$ python3 tenki.py
tenki.py を実行中… __name__ = __main__
Tokyo: 21℃
$ python3 -c "import tenki"
tenki.py を実行中… __name__ = tenki

import はファイルを上から全部実行するのでした。だから、tenki.py の一番下に動作確認のための show(21) を裸で書いておくと、import されるたびにそれも動いてしまいます。そこで、

python
if __name__ == "__main__":
    show(21)

と書いておくと、直接実行したときだけ動き、部品として import されたときは動かないファイルになります。モジュールとしても、スクリプトとしても使える書き方です。

JS(Node の CommonJS)にも if (require.main === module) という似た書き方がありますが、あまり使われません。Python ではとてもよく使われるので、見かけたら「直接実行したときの入口だな」と読んでください。

  • JS から来た人の Python 08 ― import の正体
  • 24 / 30
  • if __name__ == "__main__": の意味
  • # tenki.py
  • $ python3 tenki.py
  • print("tenki.py を実行中… __name__ =", __name__)
  • tenki.py を実行中… __name__ = __main__
  • CITY = "Tokyo"
  • Tokyo: 21℃
  • def show(temp):
  • print(f"{CITY}: {temp}℃")
  • 直接実行 → if の中も動く
  • if __name__ == "__main__":
  • show(21)
  • $ python3 -c "import tenki"
  • tenki.py を実行中… __name__ = tenki
  • import → if の中は飛ばされる
  • 「import されたときは部品として静かに、直接実行されたときだけ動く」を1ファイルで書き分ける決まり文句
  • JS には同じ決まり文句が無い(Node の CommonJS なら require.main === module が近い)
  • ひらめき
  • 直接実行したときだけ __name__ が "__main__" になる。import されたときは "tenki"。

JS(Node)と比べる:探し方・回数・場所

ここまでの内容を、Node.js の CommonJS(require)と ESM(import)に並べます。

Node の仕組みを一言でおさらいします。require("./tenki") のように ./ や ../ で始まるものは、書いたファイルのあるフォルダを基準にした相対パスとして探します。require("lodash") のように名前だけのものは、書いたファイルのフォルダの node_modules、無ければ親フォルダの node_modules…と上の階へ遡って探します。ESM の import も、名前だけのときは同じ探し方です。

Node(require)Node(ESM)Python
自分のファイルrequire("./tenki")import … from "./tenki.js"(拡張子も書く)import tenki
名前だけのときnode_modules を親へ遡る同じsys.path を上から
探す基準書いたファイルの場所書いたファイルの場所起動したスクリプトの場所(0段目)と固定の名簿
何回実行するか1回(require.cache)1回1回(sys.modules)
キャッシュの鍵ファイルの絶対パスURL(ファイルの場所)モジュールの名前
いつ実行されるかrequire の行を通ったとき本体のコードより先にまとめてimport の行を通ったとき
入れたライブラリプロジェクトの node_modules同じその python の site-packages

いちばん大きな違いは「探す基準」です。Node は書いたファイルの場所から探すので、どのファイルから require したかで結果が変わります。Python は、名簿が1本しかないので、どのファイルに import を書いても同じ場所を探します。

もう1つは「いつ実行されるか」です。Python の import は普通の文なので、関数の中や if の中にも書けて、その行を通ったときに実行されます。ESM の import がファイルの先頭で静的にまとめて処理されるのとは違います。

  • JS から来た人の Python 08 ― import の正体
  • 25 / 30
  • JS(Node)と比べる:探し方・回数・場所
  • Node(require)
  • Node(ESM の import)
  • Python(import)
  • 自分のファイル
  • require("./tenki")
  • import … from "./tenki.js"
  • import tenki
  • 探す場所
  • node_modules を親へ遡る
  • 同じ(名前だけのとき)
  • sys.path を上から
  • 基準
  • 呼んだファイルのフォルダ
  • 呼んだファイルのフォルダ
  • 起動したスクリプト
  • 何回実行
  • 1回(require.cache)
  • 1回
  • 1回(sys.modules)
  • 覚える鍵
  • ファイルの絶対パス
  • URL(ファイルのパス)
  • モジュールの名前
  • いつ実行
  • require の行を通ったとき
  • 本体より先にまとめて
  • import の行を通ったとき
  • 入れた物の場所
  • プロジェクトの node_modules
  • 同じ
  • その python の site-packages
  • ひらめき
  • Node は「呼んだファイルの場所」から探す。Python は「1本の名簿」を上から探す。

Node は親フォルダへ遡り、Python は名簿を上から

探し方の違いを、図で並べます。

左は Node です。/Users/you/app/src/index.js で require("lodash") と書くと、Node は require.resolve.paths("lodash") で見られる順に探します。実物の形はこうです。

[
  '/Users/you/app/src/node_modules',
  '/Users/you/app/node_modules',
  '/Users/you/node_modules',
  '/Users/node_modules',
  '/node_modules',
  '/Users/you/.node_modules',
  '/Users/you/.node_libraries',
  '/usr/local/lib/node'
]

書いたファイルのフォルダから、ルート(/)まで1階ずつ上がっていき、最後にいくつかの共通の場所を見ます。書いたファイルが変われば、名簿も変わります。

右は Python です。名簿は起動したときに1本だけ作られ、どのファイルから import しても同じ名簿を使います。

NodePython
名簿はいくつrequire を書いたファイルごとに違うプログラム全体で1本
プロジェクトの奥から探したとき近い node_modules が優先関係ない。同じ名簿
0段目にあたるものなし(相対パスは ./ で書く)起動したスクリプトのフォルダ

この違いから、Python では「どこから起動したか」が効いてきます。python3 scripts/run.py のように別のフォルダのスクリプトを起動すると、0段目は scripts/ になり、プロジェクトの一番上にある tenki.py は見つからなくなります。これは第9章で実物を見ます。

  • JS から来た人の Python 08 ― import の正体
  • 26 / 30
  • Node は親フォルダへ遡り、Python は名簿を上から
  • Node:require("lodash") src/index.js から
  • Python:import requests どこから書いても
  • /node_modules
  • 0 スクリプトのあるフォルダ
  • /Users/node_modules
  • 1 …/python313.zip
  • /Users/you/node_modules
  • 2 …/lib/python3.13
  • /Users/you/app/node_modules
  • 3 …/lib-dynload
  • /Users/you/app/src/node_modules
  • 4 …/.venv/…/site-packages
  • Node の実物は require.resolve.paths("lodash") で見られる(呼んだ場所から / まで、最後に共通の場所)
  • Python の名簿は1本。どのファイルから import しても同じ(0段目は起動したスクリプトで決まる)
  • ひらめき
  • Python では、近くのフォルダにあっても名簿に無ければ見ない。場所は名簿がすべて。

よくある事故:自分のファイル名が、本物を隠す

前に予告した事故の実物です。練習用のフォルダ /Users/you/practice に、JSON を試すファイルを json.py という名前で作りました。

python
# json.py
import json
print(json.dumps({"a": 1}))

実行すると、こうなります。

$ python3 json.py
Traceback (most recent call last):
  File "/Users/you/practice/json.py", line 1, in <module>
    import json
  File "/Users/you/practice/json.py", line 2, in <module>
    print(json.dumps({"a": 1}))
AttributeError: module 'json' has no attribute 'dumps' (consider renaming
'/Users/you/practice/json.py' since it has the same name as the standard library
module named 'json' and prevents importing that standard library module)

import json は名簿の0段目(practice フォルダ)で、自分自身の json.py を見つけてしまいました。json.py は __main__ として動いている途中で、もう一度「json」という名前のモジュールとして上から実行されます。Traceback に json.py が2回出てくるのはそのためです。その json.py には dumps が無いので、「json に dumps は無い」と言われます。

Python 3.13 からは、括弧の中のように「標準ライブラリと同じ名前だから、名前を変えて」と教えてくれるようになりました。ただし、requests.py のように pip で入れたライブラリと同じ名前の場合は、筆者が試した範囲では、そのファイル自身を実行したときにしかヒントが出ず、main.py から import した場合はただの AttributeError: module 'requests' has no attribute 'get' でした。

付けてしまいがちな名前隠してしまうもの
json.py・random.py・email.py・test.py標準ライブラリ
requests.py・fastapi.py・numpy.py入れたライブラリ

直すには、ファイルの名前を変え、同じフォルダにできた __pycache__ も消しておくと確実です。

  • JS から来た人の Python 08 ― import の正体
  • 27 / 30
  • よくある事故:自分のファイル名が、本物を隠す
  • 書類
  • json.py(自作)
  • 本
  • 本物の json
  • 練習用に付けた名前
  • 0段目で先に
  • 2段目。もう見られない
  • $ python3 json.py
  • File "/Users/you/practice/json.py", line 2, in <module>
  • print(json.dumps({"a": 1}))
  • AttributeError: module 'json' has no attribute 'dumps' (consider renaming
  • '/Users/you/practice/json.py' since it has the same name as the standard library
  • module named 'json' and prevents importing that standard library module)
  • 3.13 は、標準ライブラリと同じ名前なら「名前を変えて」と教えてくれる(上の括弧の中)
  • pip で入れた物(requests など)と同じ名前だと、教えてくれないこともある
  • ひらめき
  • json.py や requests.py を自分で作ると、0段目で先に見つかり、本物に届かない。

ModuleNotFoundError:名簿の最後まで無かった

import でいちばんよく見るエラーがこれです。

Traceback (most recent call last):
  File "/Users/you/tenki-app/main.py", line 3, in <module>
    import requests
ModuleNotFoundError: No module named 'requests'

意味はこの章の言葉で言えば、「名簿(sys.path)のどの段にも、requests が無かった」です。原因は、名簿が思っていたのと違うか、置いた場所が違うか、名前が違うかのどれかです。

原因よくある場面確かめ方
入れていないclone したばかりpip list に無い(第11章)
別の python で動かしたpython3 と .venv/bin/python を取り違えたimport sys; print(sys.executable)
別の venv に入れたactivate を忘れた・別のプロジェクトの venvsys.path の最後の段を見る(第12章)
配布名と import 名が違うpip install pillow なのに import pillow正しくは import PIL(第11章)
起動した場所が違う別のフォルダのスクリプトを起動したsys.path[0] を見る(第9章)

どの原因でも、確かめる方法は同じです。エラーになった python と同じ python で `print(sys.path)` を出し、目当てのフォルダが名簿にあるかを見ます。名簿にフォルダがあり、その中に目当てのファイルがあれば、必ず見つかります。無ければ、見つからないのが正しい動きです。

import のエラーは、慣れないうちは「Python の機嫌」のように見えます。でも、仕組みは「名簿を上から探す」だけなので、名簿と置き場所を見比べれば、必ず原因にたどり着けます。

  • JS から来た人の Python 08 ― import の正体
  • 28 / 30
  • ModuleNotFoundError:名簿の最後まで無かった
  • $ python3 main.py
  • 原因
  • 確かめ方
  • Traceback (most recent call last):
  • File ".../main.py", line 3, in <module>
  • 入れていない
  • pip list に無い(第11章)
  • import requests
  • ModuleNotFoundError: No module named
  • 別の python で動かした
  • sys.executable を見る
  • 'requests'
  • venv が違う
  • sys.path の最後を見る
  • 名前の違い
  • pillow → import PIL
  • 起動した場所が違う
  • sys.path[0] を見る
  • import が失敗したら、同じ python で print(sys.path) を出し、そこに目当てのフォルダがあるかを見る
  • どの python で動いているかは第1・2章、venv は第12章でくわしく扱う
  • ひらめき
  • エラーの意味は「名簿のどのフォルダにも無い」。原因は名簿か、置き場所か、名前のどれか。

tenki を2つのファイルに分ける

この章の内容を使って、tenki を2つのファイルに分けます。

ファイル役目
tenki.py天気を取る(fetch)・表示する(show)という部品
main.py部品を組み合わせて動かす入口
python
# tenki.py
CITY = "Tokyo"

def fetch(city):
    # 第11章で requests に置き換える
    return {"city": city, "temp": 21}

def show(data):
    print(f"{data['city']}: {data['temp']}℃")
python
# main.py
import tenki

if __name__ == "__main__":
    data = tenki.fetch(tenki.CITY)
    tenki.show(data)
$ cd ~/tenki-app
$ python3 main.py
Tokyo: 21℃

python3 main.py と起動すると、main.py のあるフォルダ(tenki-app)が名簿の0段目になり、同じフォルダの tenki.py が見つかります。tenki.py には print も入口も置かず、import されても何も起きない部品にしておくのがコツです。そうしておけば、後でテスト(第15章)や Web API(第17章)から tenki を import したときにも、余計なことが起きません。

ファイルが増えてきたら、次は tenki/ というフォルダにまとめたくなります。それが次の章のパッケージです。

  • JS から来た人の Python 08 ― import の正体
  • 29 / 30
  • tenki を2つのファイルに分ける
  • フォルダ
  • tenki-app/
  • # tenki.py
  • # main.py
  • 書類
  • main.py
  • CITY = "Tokyo"
  • import tenki
  • 書類
  • tenki.py
  • def fetch(city):
  • # 第11章で requests に置き換える
  • if __name__ == "__main__":
  • tenki-app で
  • return {"city": city, "temp": 21}
  • data = tenki.fetch(tenki.CITY)
  • tenki.show(data)
  • python3 main.py
  • と起動すると、
  • def show(data):
  • print(f"{data['city']}: {data['temp']}℃")
  • sys.path[0] が
  • $ python3 main.py
  • Tokyo: 21℃
  • tenki-app になる
  • tenki.py は「import されても何も起きない部品」にしておく。print や入口は main.py だけに置く
  • 後でテスト(第15章)や Web API(第17章)から import したときに、余計なことが起きない
  • ひらめき
  • 天気の処理は tenki.py、起動するだけの main.py。同じフォルダに置けば import で届く。

まとめ:import は「名簿を上から探して、1回だけ実行する」

この章で見たことをまとめます。

用語意味
モジュールimport できる単位。いちばん基本は .py ファイル1つ(tenki.py → tenki)
sys.modules一度 import したモジュールの棚(辞書)。2回目以降はここから返す
sys.path探すフォルダの名簿。スクリプトのフォルダ → 標準ライブラリ → site-packages の順
上から実行見つけたファイルは最後まで実行され、残った名前がモジュールの中身になる
__file__実際に使われたファイルのパス。迷ったらまずこれを見る
__name__import されたらモジュールの名前、直接実行なら "__main__"
JS との違いnode_modules を親へ遡らない。探す場所は1本の名簿がすべて

3つの import の答え合わせです。

import見つかった場所誰が置いたか
import tenki0段目:/Users/you/tenki-app/tenki.pyあなた
import json2段目:…/lib/python3.13/json/__init__.pyPython のインストーラー
import requests4段目:…/.venv/lib/python3.13/site-packages/requests/__init__.pypip

json と requests は、ファイルではなく __init__.py を持つフォルダでした。では、自分の tenki も tenki/ フォルダに分けたらどう import するのでしょうか。import tenki.api の点は何を意味するのでしょうか。次の第9章「パッケージとフォルダ構成」で見ていきます。

  • JS から来た人の Python 08 ― import の正体
  • 30 / 30
  • まとめ:import は「名簿を上から探して、1回だけ実行する」
  • 用語
  • 意味
  • モジュール
  • import できる単位。ファイル1つ(tenki.py → tenki)
  • sys.modules
  • 一度読んだモジュールの棚。2回目以降はここから返す
  • sys.path
  • 探すフォルダの名簿。スクリプトの場所 → 標準ライブラリ → site-packages
  • 実行
  • 見つけたファイルは上から最後まで実行され、その結果がモジュールの中身になる
  • __file__
  • 実際に使われたファイルのパス。迷ったらまずこれ
  • __name__
  • import されたら名前、直接実行なら "__main__"
  • JS との違い
  • node_modules を遡らない。探す場所は名簿がすべて
  • ひらめき
  • 次の章:ファイルが増えたらフォルダに分けたい。フォルダを import するとどうなる?

0 件のコメント

読み込み中…

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