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

Python 09:パッケージとフォルダ構成 ― フォルダを import すると何が起きるか

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

ファイルが増えた tenki を tenki/ フォルダにまとめ、パッケージにします。import tenki.display の1行で、フォルダの木のどのファイルがどの順に実行されるのかを実際の出力で1段ずつ追い、__init__.py の役目、点とフォルダの対応、相対 import とそのエラー、python -m と __main__.py、標準ライブラリの json と pip で入れた requests の実物のフォルダ、__init__.py の無いフォルダ、別のフォルダから起動したときの ModuleNotFoundError、src レイアウトまでを扱います。

ファイルが増えてきた。フォルダに分けたら、どう import する?

第8章で tenki を main.py と tenki.py の2つに分けました。ところが、天気を取ってくる処理、画面に出す処理、摂氏と華氏を変換する処理…と足していくうちに、tenki.py がまた長くなってきました。

役目ごとにファイルを分け、関係するものは1つのフォルダにまとめたくなります。JS なら、src/tenki/ のようなフォルダを作って、中に api.js・display.js を置き、index.js から外に見せる、という形をよく作ります。

Python でも同じことができます。ただ、ここで第8章の知識を当てはめると、疑問が湧いてきます。

疑問答えのありか
フォルダも import できるの?「パッケージ」の話
import tenki.api の点(.)は何?点とフォルダの対応
フォルダの中のファイルどうしは、どう import し合う?相対 import
json や requests は、中がどうなっている?実物のフォルダを見る

第8章で、json も requests も、見つかったのは1つの .py ファイルではなく json/・requests/ というフォルダでした。中には __init__.py がありました。この章は、その「フォルダの import」を正面から扱います。

実物の出力を見せるために、この章でも各ファイルの先頭に print("… を実行") を仕込んだ tenki を、Python 3.13 で実際に動かしています。

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

  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 1 / 22
  • ファイルが増えてきた。フォルダに分けたら、どう import する?
  • 書類
  • tenki.py(400行)
  • 書類
  • api.py
  • 疑問
  • 取得も表示も変換も1本
  • 分けたい
  • 天気を取ってくる
  • フォルダも import できる?
  • import tenki.api の点は何?
  • 書類
  • display.py
  • フォルダの中どうしは?
  • 画面に出す
  • json や requests も
  • 中はこうなっている?
  • 書類
  • units/temp.py
  • ℃と℉を変える
  • 第8章で、import は sys.path の名簿を上から探して、見つけたファイルを実行することを見た
  • 見つかるのが「ファイル」ではなく「フォルダ」だったら? json と requests はまさにそうだった
  • ひらめき
  • tenki.py に天気の取得・表示・単位の変換が全部入って長くなった。フォルダで整理したい。

一言でいうと:パッケージは「目印の付いたフォルダ」

パッケージは、`__init__.py` というファイルが入ったフォルダです。__init__.py は「このフォルダは import できる部品のまとまりです」という目印で、中身は空でもかまいません。

パッケージの中の .py ファイルはサブモジュール、中のフォルダ(これも __init__.py 入り)はサブパッケージと呼びます。

ディスクの上Python での呼び方import の名前
tenki/(__init__.py 入り)パッケージtenki
tenki/api.pyサブモジュールtenki.api
tenki/units/(__init__.py 入り)サブパッケージtenki.units
tenki/units/temp.pyサブモジュールtenki.units.temp

import の名前に出てくる点(.)は、フォルダの区切り(/)です。import tenki.units.temp は、「tenki フォルダの中の、units フォルダの中の、temp.py」という道順を表しています。住所の「東京都・千代田区・丸の内」を、大きいほうから順に並べるのと同じです。

「パッケージ」という言葉には、もう1つ「pip で入れる配布物」という意味もあります(第11章)。この章で言うパッケージは、フォルダとしてのパッケージのほうです。混ざりやすいので、第10章で言葉を整理します。

  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 2 / 22
  • 一言でいうと:パッケージは「目印の付いたフォルダ」
  • フォルダ
  • tenki/(パッケージ)
  • import tenki.units.temp
  • __init__.py
  • # ディスクの上では
  • 目印。フォルダを import すると実行される
  • tenki/units/temp.py
  • api.py
  • サブモジュール tenki.api
  • units/
  • 点で区切った名前が、そのままフォルダの道順になる
  • サブパッケージ tenki.units
  • 住所を「東京都 → 千代田区 → 丸の内」と
  • 大きいほうから書くのと同じ
  • ひらめき
  • __init__.py の入ったフォルダがパッケージ。import の点(.)は、フォルダの区切り(/)。

tenki をパッケージにした、フォルダの実物

tenki を、図のようなフォルダの形にしました。

tenki-app/
├── main.py
└── tenki/
    ├── __init__.py
    ├── __main__.py
    ├── api.py
    ├── display.py
    └── units/
        ├── __init__.py
        └── temp.py
ファイル役目
tenki/__init__.pyパッケージ tenki の目印。import tenki したときに実行される
tenki/api.py天気を取ってくる(今はダミーの値を返す。第11章で requests に)
tenki/display.py画面に出す
tenki/units/temp.py摂氏から華氏への変換
tenki/__main__.pypython -m tenki で起動したときの入口(後で見る)
main.pyプロジェクトの入口。tenki を import して使う

1つ気をつけたいのは、tenki-app(プロジェクトのフォルダ)と tenki(パッケージ)は別物だということです。import で使う名前は、内側の tenki です。外側の tenki-app は、第8章で見たとおり、main.py を起動したときに名簿(sys.path)の0段目になるフォルダです。その0段目の中に tenki/ があるので、import tenki で見つかります。

プロジェクトのフォルダ名は自由ですが、パッケージのフォルダ名は Python の名前として使える形(英小文字・数字・アンダースコア)にします。tenki-app のようなハイフン入りの名前は、import では書けません。

  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 3 / 22
  • tenki をパッケージにした、フォルダの実物
  • フォルダ
  • tenki-app/
  • ファイル
  • import で書く名前
  • 書類
  • main.py
  • フォルダ
  • tenki/
  • tenki/__init__.py
  • tenki
  • 書類
  • __init__.py
  • tenki/api.py
  • tenki.api
  • 書類
  • __main__.py
  • 書類
  • api.py
  • tenki/display.py
  • tenki.display
  • 書類
  • display.py
  • tenki/units/__init__.py
  • tenki.units
  • フォルダ
  • units/
  • tenki/units/temp.py
  • tenki.units.temp
  • 書類
  • __init__.py
  • 書類
  • temp.py
  • tenki/__main__.py
  • python -m tenki の入口
  • __init__.py の中身は空でもよい。「このフォルダはパッケージです」という目印になる
  • tenki-app(プロジェクト)と tenki(パッケージ)は別物。import で使う名前は内側の tenki
  • ひらめき
  • tenki-app の中に tenki/ フォルダ。その中に .py が並び、さらに units/ フォルダがある。

import a.b.c とフォルダは、1対1で対応する

点で区切った名前と、フォルダの道順は、そのまま対応します。

python
import tenki              # tenki/__init__.py
import tenki.api          # tenki/api.py
import tenki.units        # tenki/units/__init__.py
import tenki.units.temp   # tenki/units/temp.py

規則は2つだけです。

位置何でなければならないか
点の左側(tenki、units)パッケージ(フォルダ)。ファイルの「中」には入れない
いちばん右モジュール(.py ファイル)かパッケージ(フォルダ)のどちらでもよい

だから import tenki.api.fetch とは書けません。fetch は api.py の中の関数で、フォルダでもファイルでもないからです。関数を取り出すときは from tenki.api import fetch と書きます(第8章の from)。

JS と比べると、Node の require("./tenki/units/temp") の / が、Python では . になっていると考えるとわかりやすいでしょう。ただし、Python には ./ のような「ここから」の印がありません。import tenki.units.temp の最初の tenki は、名簿(sys.path)の中から探されます。探し方は第8章とまったく同じです。

  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 4 / 22
  • import a.b.c とフォルダは、1対1で対応する
  • import tenki
  • tenki/__init__.py
  • import tenki.api
  • tenki/api.py
  • import tenki.units
  • tenki/units/__init__.py
  • import tenki.units.temp
  • tenki/units/temp.py
  • 名前の形
  • ディスクの上
  • 呼び方
  • tenki
  • tenki/ フォルダ(__init__.py 入り)
  • パッケージ
  • tenki.api
  • tenki/api.py
  • サブモジュール
  • tenki.units
  • tenki/units/ フォルダ
  • サブパッケージ
  • ひらめき
  • 点の左はフォルダ(パッケージ)、いちばん右はファイルかフォルダ。点を / に置き換えると道順になる。

import tenki.display ①:まず「tenki」を名簿で探す

main.py にはこう書いてあります。

python
# main.py
import tenki.display
tenki.display.show("Osaka")

この1行で何が起きるのかを、図のフォルダの木の上で1段ずつ追いかけます。黒い小包が「いま探しているもの・実行しているもの」、黄色がいま実行中のファイル、緑が実行済みのファイルです。番号の札は、実行された順番です。

公式ドキュメント(The import system)によると、import tenki.display は左の親から順に import します。

順番import するもの
1tenki
2tenki.display

まず tenki です。第8章の手順どおり、棚(sys.modules)に無いので、名簿を上から探します。名簿の0段目は、main.py を起動した tenki-app です。そこに tenki/ というフォルダがあり、中に __init__.py がある。見つかりました。

ここまでは、tenki.py というファイルが見つかった第8章と同じです。違うのは、見つかったのがフォルダだということです。フォルダは実行できません。では、何が実行されるのでしょうか。

  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 5 / 22
  • import tenki.display ①:まず「tenki」を名簿で探す
  • フォルダ
  • tenki-app/
  • ← sys.path[0]
  • # main.py
  • 書類
  • main.py
  • import tenki.display
  • フォルダ
  • tenki/
  • tenki.display.show("Osaka")
  • tenki を探す
  • 書類
  • __init__.py
  • 書類
  • __main__.py
  • 書類
  • api.py
  • 書類
  • display.py
  • フォルダ
  • units/
  • 書類
  • __init__.py
  • 書類
  • temp.py
  • import tenki.display は「tenki を import → その中の display を import」の2段。左の親から順に
  • tenki を探す手順は第8章と同じ(棚 → 名簿を上から)。見つかったのはファイルではなくフォルダ
  • ひらめき
  • 点の左から順に。最初に探すのは tenki。sys.path[0] の tenki-app に tenki/ フォルダがある。

import tenki.display ②:tenki/__init__.py を上から実行

フォルダを import すると、その中の `__init__.py` が上から実行されます。__init__.py を実行した結果が、モジュール tenki の中身になります。

python
# tenki/__init__.py
print("tenki/__init__.py を実行")
from .api import fetch
__version__ = "0.1.0"

1行目の print が動き、出力に「tenki/__init__.py を実行」が出ました。これが1番目です。

続く2行目、from .api import fetch の .api は「同じパッケージの中の api」という意味です(相対 import。後でくわしく見ます)。つまり、tenki.api が必要になりました。

ここで Python は、__init__.py の実行を2行目でいったん止めて、先に tenki.api を import しに行きます。import は「その行を通ったときに実行される文」でした(第8章)。途中の import に出会ったら、そちらを済ませてから戻ってくる、という動きです。

関数の中で別の関数を呼ぶと、呼んだ先が終わってから続きに戻るのと同じです。

  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 6 / 22
  • import tenki.display ②:tenki/__init__.py を上から実行
  • フォルダ
  • tenki-app/
  • # tenki/__init__.py
  • 書類
  • main.py
  • print("tenki/__init__.py を実行")
  • フォルダ
  • tenki/
  • from .api import fetch
  • __version__ = "0.1.0"
  • 書類
  • __init__.py
  • 1
  • tenki を実行
  • 書類
  • __main__.py
  • 書類
  • api.py
  • $ python3 main.py
  • 書類
  • display.py
  • tenki/__init__.py を実行
  • フォルダ
  • units/
  • 書類
  • __init__.py
  • 書類
  • temp.py
  • __init__.py の中の from .api import fetch で、同じフォルダの api.py が必要になる
  • → 実行を途中で止めて、先に tenki.api を import しに行く
  • ひらめき
  • フォルダを import すると、中の __init__.py が実行される。これがモジュール tenki の中身になる。

import tenki.display ③:途中で api.py が実行される

tenki.api は、tenki/ フォルダの中の api.py です。上から実行され、出力に「tenki/api.py を実行」が出ます。これが2番目です。

python
# tenki/api.py
print("tenki/api.py を実行")

def fetch(city):
    return {"city": city, "temp_c": 21}

ここで大事な点があります。api.py は、名簿(sys.path)を上から探し直して見つけたのではありません。

公式ドキュメントによると、パッケージは `__path__` という自分専用の小さな名簿を持っていて、サブモジュールはそこで探されます。tenki の __path__ は、tenki フォルダ1つだけが入ったリストです。

>>> import tenki
>>> tenki.__path__
['/Users/you/tenki-app/tenki']
探すものどの名簿で探すか
tenki(いちばん左)sys.path(全体の名簿)
tenki.api など(点の右)tenki.__path__(tenki フォルダ)

だから、仮に名簿のどこか別の場所に api.py というファイルがあっても、tenki.api がそれと混ざることはありません。api.py が終わると、__init__.py の3行目に戻り、__version__ を作って最後まで実行し終わります。

  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 7 / 22
  • import tenki.display ③:途中で api.py が実行される
  • フォルダ
  • tenki-app/
  • # tenki/api.py
  • 書類
  • main.py
  • print("tenki/api.py を実行")
  • フォルダ
  • tenki/
  • def fetch(city):
  • return {"city": city, "temp_c": 21}
  • 書類
  • __init__.py
  • 1
  • 書類
  • __main__.py
  • 書類
  • api.py
  • 2
  • tenki.api
  • $ python3 main.py
  • 書類
  • display.py
  • tenki/__init__.py を実行
  • フォルダ
  • units/
  • tenki/api.py を実行
  • 書類
  • __init__.py
  • 書類
  • temp.py
  • api.py はフォルダ tenki/ の中で探される。名簿(sys.path)をもう一度上から見るのではない
  • 探す場所は tenki.__path__(= tenki/ フォルダ)。パッケージは自分専用の小さな名簿を持つ
  • ひらめき
  • __init__.py の2行目が tenki.api を呼ぶ。api.py を上から実行して、__init__.py の続きに戻る。

import tenki.display ④:次に display.py

tenki の import が終わりました。次は点の右、tenki.display です。tenki の __path__(tenki フォルダ)の中で display.py が見つかり、上から実行されます。3番目です。

python
# tenki/display.py
print("tenki/display.py を実行")
from . import api
from .units import temp

def show(city):
    d = api.fetch(city)
    print(f"{d['city']}: {d['temp_c']}℃ / {temp.c_to_f(d['temp_c'])}℉")

2行目の from . import api を見てください。api は②③でもう実行済みで、棚(sys.modules)に tenki.api があります。だから api.py はもう一度実行されることはなく、棚から取り出して api という名前を付けるだけです(第8章:1回しか実行されない)。出力にも「tenki/api.py を実行」は2回目が出ていません。

行棚に…起きること
from . import apitenki.api がある名前を付けるだけ
from .units import temptenki.units が無い探して実行しに行く

3行目の from .units import temp では、tenki.units と tenki.units.temp がまだ棚にありません。そこで display.py の実行をまた止めて、units へ向かいます。

  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 8 / 22
  • import tenki.display ④:次に display.py
  • フォルダ
  • tenki-app/
  • # tenki/display.py
  • 書類
  • main.py
  • print("tenki/display.py を実行")
  • フォルダ
  • tenki/
  • from . import api
  • from .units import temp
  • 書類
  • __init__.py
  • 1
  • def show(city): …
  • 書類
  • __main__.py
  • 書類
  • api.py
  • 2
  • $ python3 main.py
  • 書類
  • display.py
  • 3
  • tenki.display
  • tenki/__init__.py を実行
  • フォルダ
  • units/
  • tenki/api.py を実行
  • tenki/display.py を実行
  • 書類
  • __init__.py
  • 書類
  • temp.py
  • display.py の from . import api は、api が棚にもうあるので実行されない(第8章:1回だけ)
  • 3行目の from .units import temp で、今度はサブパッケージ units へ
  • ひらめき
  • tenki が済んだので、点の右の display へ。tenki/ フォルダの中の display.py を実行する。

import tenki.display ⑤:units/ の __init__.py、そして temp.py

tenki.units.temp を使うには、左の親から順に、tenki → tenki.units → tenki.units.temp がすべて実行されている必要があります。tenki は済んでいるので、残りは2つです。

順番ファイル出力
4tenki/units/__init__.pytenki/units/__init__.py を実行
5tenki/units/temp.pytenki/units/temp.py を実行

units もフォルダ(サブパッケージ)なので、まずその __init__.py が実行されます。この章では出力を見せるために print を1行だけ書いていますが、ふだんは空のファイルで十分です。

python
# tenki/units/temp.py
print("tenki/units/temp.py を実行")

def c_to_f(c):
    return c * 9 / 5 + 32

temp.py が終わると、止めていた display.py の3行目に戻り、temp という名前が付き、残りの def show が実行されて display.py が終わります。

このように、import は深さ優先で進みます。途中で出てきた import を先に最後まで片付け、終わったら元の場所に戻る。どれだけファイルが多くても、「出会った順に、1回ずつ」です。

  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 9 / 22
  • import tenki.display ⑤:units/ の __init__.py、そして temp.py
  • フォルダ
  • tenki-app/
  • # tenki/units/temp.py
  • 書類
  • main.py
  • print("tenki/units/temp.py を実行")
  • フォルダ
  • tenki/
  • def c_to_f(c):
  • return c * 9 / 5 + 32
  • 書類
  • __init__.py
  • 1
  • 書類
  • __main__.py
  • 書類
  • api.py
  • 2
  • $ python3 main.py
  • 書類
  • display.py
  • 3
  • tenki/__init__.py を実行
  • フォルダ
  • units/
  • tenki/api.py を実行
  • tenki/display.py を実行
  • 書類
  • __init__.py
  • 4
  • tenki/units/__init__.py を実行
  • tenki/units/temp.py を実行
  • 書類
  • temp.py
  • 5
  • tenki.units.temp
  • tenki.units.temp を使うには、tenki → tenki.units → tenki.units.temp の順にすべて実行されている必要がある
  • tenki は済んでいるので、残りの units/__init__.py と temp.py だけが実行された
  • ひらめき
  • units もフォルダなので、先に units/__init__.py、次に temp.py。親から子への順番は同じ。

import tenki.display ⑥:できあがり

main.py の import tenki.display の1行が終わりました。実際の出力の全体はこうです。

$ python3 main.py
tenki/__init__.py を実行
tenki/api.py を実行
tenki/display.py を実行
tenki/units/__init__.py を実行
tenki/units/temp.py を実行
Osaka: 21℃ / 69.8℉

最後の1行は、main.py の2行目 tenki.display.show("Osaka") の結果です。棚には tenki で始まるモジュールが5つ入りました。

棚の名前ファイル実行の順
tenkitenki/__init__.py1
tenki.apitenki/api.py2
tenki.displaytenki/display.py3
tenki.unitstenki/units/__init__.py4
tenki.units.temptenki/units/temp.py5

__main__.py は実行されていません。これは python -m tenki と起動したときだけの入口です。

では、main.py に付いた名前は何でしょう。import tenki.display で付くのは、いちばん左の `tenki` だけです。display という名前は main.py にはありません(print(display) は NameError になります)。その代わり、サブモジュールを import すると、親のモジュールの中に子の名前が付けられる決まりがあるので、tenki.display とたどって届きます。

  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 10 / 22
  • import tenki.display ⑥:できあがり
  • フォルダ
  • tenki-app/
  • >>> sorted(m for m in sys.modules if m.startswith("tenki"))
  • 書類
  • main.py
  • ['tenki', 'tenki.api', 'tenki.display',
  • フォルダ
  • tenki/
  • 'tenki.units', 'tenki.units.temp']
  • 書類
  • __init__.py
  • 1
  • 書類
  • __main__.py
  • 書類
  • api.py
  • 2
  • $ python3 main.py
  • 書類
  • display.py
  • 3
  • tenki/__init__.py を実行
  • フォルダ
  • units/
  • tenki/api.py を実行
  • tenki/display.py を実行
  • 書類
  • __init__.py
  • 4
  • tenki/units/__init__.py を実行
  • tenki/units/temp.py を実行
  • 書類
  • temp.py
  • 5
  • Osaka: 21℃ / 69.8℉
  • __main__.py は実行されていない。python -m tenki で起動したときだけの入口(後で見る)
  • main.py に付く名前は tenki だけ。display は tenki の中の名前として tenki.display で届く
  • ひらめき
  • 5つのファイルが1回ずつ実行され、棚には5つのモジュール。main.py には「tenki」という名前だけ。

__init__.py の役目:パッケージの「表の顔」

__init__.py は目印であると同時に、`import tenki` したときの `tenki` そのものです。ここに書いた名前が、tenki.〇〇 として外から使えます。

tenki の __init__.py には from .api import fetch と書いてあるので、利用する側は tenki.api.fetch と奥まで書かなくても、tenki.fetch で使えます。実際に確かめると、2つは同じ関数です。

>>> import tenki
>>> tenki.fetch is tenki.api.fetch
True

この書き方は、ライブラリでとてもよく使われます。requests の __init__.py を開くと、実物にこう書いてあります。

python
# site-packages/requests/__init__.py(抜粋)
from .api import delete, get, head, options, patch, post, put, request
from .models import PreparedRequest, Request, Response
from .sessions import Session, session

requests.get(...) と書けるのは、get が requests/api.py に書かれていて、__init__.py がそれを表に並べているからです。JS で index.js から export { get } from "./api.js" と書き出すのと同じ役目です。

__init__.py の書き方使う側
空っぽimport tenki.api と中まで書いて使う
よく使う物を並べるimport tenki だけで tenki.fetch が使える

ただし、__init__.py は import のたびに必ず実行されるので、重い処理や print を置かないのが決まりです。この章の print は、順番を見せるための仕込みです。

  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 11 / 22
  • __init__.py の役目:パッケージの「表の顔」
  • # tenki/__init__.py
  • # site-packages/requests/__init__.py(抜粋)
  • from .api import fetch
  • from .api import delete, get, head, options,
  • __version__ = "0.1.0"
  • patch, post, put, request
  • from .models import PreparedRequest, Request, Response
  • from .sessions import Session, session
  • >>> import tenki
  • >>> tenki.fetch
  • requests.get が使えるのは、
  • <function fetch at 0x…>
  • requests/api.py に書かれた get を
  • >>> tenki.fetch is tenki.api.fetch
  • __init__.py が表に並べているから
  • True
  • 空の __init__.py でもよい。そのときは
  • import tenki.api と中まで書いて使う
  • ひらめき
  • __init__.py に書いた名前が、import tenki したときの tenki.〇〇。よく使う物をここに集める。

相対 import:点1つは「同じパッケージ」、点2つは「1つ上」

パッケージの中のファイルどうしは、相対 import で互いを呼べます。

python
# tenki/display.py の中で
from . import api          # tenki.api
from .units import temp    # tenki.units.temp

# tenki/units/temp.py の中で
from .. import api         # tenki.api
書き方意味
from . import x自分と同じパッケージの x
from .mod import x同じパッケージの mod の中の x
from .. import x1つ上のパッケージの x

点の数が、パッケージを上がる回数です。相対 import は from の形でしか書けません(import .api は文法エラー)。

基準になるのは「ファイルがディスクのどこにあるか」ではなく、「そのモジュールがどのパッケージに属しているか」です。モジュールには __package__ という名前が自動で入っていて、display.py なら 'tenki' です。. はこの 'tenki'、.. はその1つ上を指します。

もちろん、絶対の形 from tenki import api で書くこともできます。相対の形の良いところは、パッケージの名前を後で変えても中の import を直さなくてよいことです。どちらを使うかはプロジェクトでそろえれば十分です。

JS の "./api.js" は「このファイルのあるフォルダ」が基準でした。Python の . は「このモジュールのパッケージ」が基準です。ふだんは同じ場所を指しますが、この違いが次に見るエラーの原因になります。

  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 12 / 22
  • 相対 import:点1つは「同じパッケージ」、点2つは「1つ上」
  • フォルダ
  • tenki-app/
  • # tenki/display.py の中で
  • 書類
  • main.py
  • from . import api # tenki.api
  • フォルダ
  • tenki/
  • from .units import temp # tenki.units.temp
  • 書類
  • __init__.py
  • # tenki/units/temp.py の中で
  • 書類
  • __main__.py
  • from .. import api # tenki.api
  • 書類
  • api.py
  • 書類
  • display.py
  • 書き方
  • 意味(display.py から見て)
  • フォルダ
  • units/
  • from . import x
  • 同じ tenki/ の中の x
  • 書類
  • __init__.py
  • 書類
  • from .. import x
  • 1つ上のパッケージの中の x
  • temp.py
  • 基準は「ファイルの場所」ではなく「そのモジュールが属するパッケージ」(__package__ が 'tenki')
  • from . import api とは書けるが、import .api とは書けない(相対は from の形だけ)
  • ひらめき
  • パッケージの中では、仲間を from . import api と書ける。点の数がフォルダを上がる回数。

パッケージの中のファイルを、直接実行するとエラー

display.py の動きを確かめたくて、直接実行してみます。

$ python3 tenki/display.py
Traceback (most recent call last):
  File "/Users/you/tenki-app/tenki/display.py", line 2, in <module>
    from . import api
ImportError: attempted relative import with no known parent package

「親のパッケージがわからないのに、相対 import しようとした」というエラーです。ファイルのパスを指定して直接実行すると、display.py はパッケージ tenki の一員ではなく、ただのスクリプト(`__main__`)として動きます。__package__ が空なので、. がどこを指すのか決まりません。

直すには、ファイルのパスではなく、モジュールの名前で起動します。

bash
cd ~/tenki-app
python3 -m tenki.display

-m を付けると、Python は tenki.display という名前を名簿から探し、tenki パッケージを import したうえで display を実行します。実際に動かすと、__init__.py から順に実行され、エラーは出ません。

起動のしかたdisplay.py の立場相対 import
python3 tenki/display.pyただのスクリプト使えない
python3 -m tenki.displaytenki の一員(名前は __main__)使える

公式ドキュメントによると、-m で起動したときの名簿の0段目は、スクリプトのフォルダではなく今いるフォルダです。だから tenki-app に cd してから打つ必要があります。

  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 13 / 22
  • パッケージの中のファイルを、直接実行するとエラー
  • $ python3 tenki/display.py
  • Traceback (most recent call last):
  • File "/Users/you/tenki-app/tenki/display.py", line 2, in <module>
  • from . import api
  • ImportError: attempted relative import with no known parent package
  • NG
  • python3 tenki/display.py
  • OK
  • python3 -m tenki.display
  • ただのスクリプト。__name__ は "__main__"、親パッケージ無し
  • tenki-app で打つ。名前で起動するので tenki の一員になる
  • python -m は名前で起動する。名簿で探し、パッケージの一員として読み込んでから実行する
  • このときの sys.path[0] は今いるフォルダ。だから tenki-app で打つ
  • ひらめき
  • python3 tenki/display.py だと「パッケージの一員」ではなくなり、点の基準が無くなる。

python -m tenki と __main__.py

python3 -m tenki のように、パッケージを -m で起動すると、その中の `__main__.py` が実行されます。

python
# tenki/__main__.py
from tenki.display import show
show("Tokyo")
$ cd ~/tenki-app
$ python3 -m tenki
tenki/__init__.py を実行
tenki/api.py を実行
tenki/display.py を実行
tenki/units/__init__.py を実行
tenki/units/temp.py を実行
Tokyo: 21℃ / 69.8℉

__init__.py から順に実行され、最後に __main__.py が動いています。

ファイルいつ実行されるか
__init__.pyパッケージが import されたとき(毎回の入口)
__main__.pypython -m パッケージ名 で起動したとき(起動専用の入口)

第2章で出てきた python3 -m pip や python3 -m venv も、この仕組みです。pip も venv も、名簿のどこかにあるモジュール(パッケージ)で、-m はそれを名前で探して起動しています。「どの python の pip を動かすか」をはっきりさせられるので、pip より python3 -m pip が勧められるのでした。

第8章の if __name__ == "__main__": と役目は似ています。1ファイルのモジュールならその if、パッケージなら __main__.py が「起動されたときの入口」です。第14章では、これをさらに tenki というコマンドとして打てるようにします。

  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 14 / 22
  • python -m tenki と __main__.py
  • # tenki/__main__.py
  • from tenki.display import show
  • ファイル
  • いつ実行される
  • show("Tokyo")
  • __init__.py
  • パッケージを import したとき
  • __main__.py
  • python -m でパッケージを起動したとき
  • $ cd ~/tenki-app
  • $ python3 -m tenki
  • tenki/__init__.py を実行
  • python -m pip や python -m venv も同じ仕組み。
  • tenki/api.py を実行
  • tenki/display.py を実行
  • pip や venv というパッケージ(モジュール)を
  • tenki/units/__init__.py を実行
  • 名前で探して起動している(第2章)
  • tenki/units/temp.py を実行
  • Tokyo: 21℃ / 69.8℉
  • ひらめき
  • パッケージを -m で起動すると、中の __main__.py が実行される。パッケージの「起動用の入口」。

標準ライブラリの json も、同じ形のパッケージ

第8章で見つけた標準ライブラリの json を、もう一度開いてみます。

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

あなたの tenki/ と同じく、__init__.py と仲間の .py が並んでいるだけです。__init__.py の中にはこう書かれています。

python
# json/__init__.py(抜粋)
from .decoder import JSONDecoder, JSONDecodeError
from .encoder import JSONEncoder
import codecs

相対 import で仲間の decoder.py と encoder.py を読み、json.dumps や json.loads はこの __init__.py の中で定義されています。tenki と同じ書き方です。

REPL で __path__ と、サブモジュールの __file__ を見ると、実物の場所がわかります。

>>> import json
>>> json.__path__
['/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/json']
>>> json.decoder.__file__
'/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/json/decoder.py'

json.decoder と書くだけで届くのは、__init__.py が decoder を import した時点で、親の json の中に decoder という名前が付けられたからです(「できあがり」で見た決まり)。

tenkijson
置き場tenki-app/(名簿の0段目)…/lib/python3.13/(名簿の2段目)
形__init__.py と .py同じ
相対 importfrom .api import fetchfrom .decoder import JSONDecoder
  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 15 / 22
  • 標準ライブラリの json も、同じ形のパッケージ
  • …/Versions/3.13/lib/python3.13/json/
  • # json/__init__.py(抜粋)
  • 書類
  • __init__.py
  • from .decoder import JSONDecoder, JSONDecodeError
  • from .encoder import JSONEncoder
  • 書類
  • decoder.py
  • import codecs
  • 書類
  • encoder.py
  • >>> import json
  • 書類
  • scanner.py
  • >>> json.__path__
  • ['/Library/Frameworks/…/lib/python3.13/json']
  • 書類
  • tool.py
  • >>> json.decoder.__file__
  • '/Library/Frameworks/…/lib/python3.13/json/decoder.py'
  • ひらめき
  • …/lib/python3.13/json/ の中に __init__.py と、仲間の .py が並んでいるだけ。

pip で入れた requests も、同じ形のパッケージ

名簿の最後の段、site-packages に pip が置いた requests も見てみます。筆者の環境に入った requests 2.34.2 の中身です(__pycache__ と、型情報の目印 py.typed などは省いています)。

$ ls .venv/lib/python3.13/site-packages/requests/
__init__.py        __version__.py   _internal_utils.py  adapters.py
api.py             auth.py          certs.py            compat.py
cookies.py         exceptions.py    help.py             hooks.py
models.py          packages.py      sessions.py         status_codes.py
structures.py      utils.py

やはり __init__.py と .py の集まりです。requests.get の本体は api.py にあり、__init__.py が表に並べているのは前に見たとおりです。

これで、「ライブラリってどういう構造なの?」の答えの半分が出ました。ライブラリは、誰かが書いて配った、パッケージ(フォルダ)です。あなたの tenki/ と作りは同じで、エディタで開けば中身を読めます。特別な形式に変換された何かではありません。

あなたの tenkirequests
書いた人あなたrequests の開発者たち
置いた人あなたpip
置き場プロジェクトの中site-packages
形__init__.py と .py同じ

残りの半分、「誰がどうやって配り、pip がどうやって置くのか」「フレームワークとは何が違うのか」は、第10章と第11章で見ていきます。

  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 16 / 22
  • pip で入れた requests も、同じ形のパッケージ
  • tenki-app/.venv/lib/python3.13/site-packages/requests/
  • 本
  • __init__.py
  • certs.py
  • models.py
  • ライブラリの正体
  • __version__.py
  • compat.py
  • packages.py
  • 誰かが書いた .py の集まり。
  • エディタで開いて読める。
  • _internal_utils.py
  • cookies.py
  • sessions.py
  • requests.get は api.py に
  • adapters.py
  • exceptions.py
  • status_codes.py
  • 書かれていて、__init__.py が
  • 表に並べている。
  • api.py
  • help.py
  • structures.py
  • くわしくは第10章。
  • auth.py
  • hooks.py
  • utils.py
  • ひらめき
  • site-packages/requests/ の中身は、あなたの tenki/ と同じ。__init__.py と .py の集まり。

__init__.py が無いフォルダも import できてしまう

実は、__init__.py が無いフォルダも import できます。練習用のフォルダで試すと、エラーにならずにこう表示されます。

$ ls tools/
a.py
$ python3 -c "import tools, tools.a; print(tools)"
<module 'tools' (namespace) from ['/Users/you/practice/tools']>

(namespace) と出ています。これは名前空間パッケージという別の種類で、公式ドキュメントによると「1つのパッケージ名を、別々の場所にある複数のフォルダで分け合う」ための仕組みです。大きなライブラリが、同じ名前の下に別々の配布物を置くときなどに使われます。

ふつうのパッケージ名前空間パッケージ
__init__.pyある無い
__file__…/tenki/__init__.pyNone
表に並べる場所__init__.py がある無い
向いている用途ほとんどの場合複数の配布物で1つの名前を分け合う特殊な場合

「__init__.py は Python 3.3 から要らなくなった」という説明を見かけることがありますが、正確には「無くても別の種類として動くようになった」です。自分のコードでは、`__init__.py` を置いてふつうのパッケージにするのが素直です。置き忘れても動いてしまうので、気づかないうちに名前空間パッケージになっている、ということがあります。

  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 17 / 22
  • __init__.py が無いフォルダも import できてしまう
  • $ ls tools/
  • a.py # __init__.py が無い
  • $ python3 -c "import tools, tools.a; print(tools)"
  • <module 'tools' (namespace) from ['/Users/you/practice/tools']>
  • ふつうのパッケージ
  • 名前空間パッケージ
  • __init__.py
  • ある
  • 無い
  • __file__
  • …/tenki/__init__.py
  • None(ファイルが無い)
  • 向いている用途
  • ふつうはこちら
  • 1つの名前を複数の配布物で分け合う特殊な場合
  • ひらめき
  • __init__.py が無いと「名前空間パッケージ」という別物になる。自分のコードには置く。

よくある事故:別のフォルダのスクリプトから import できない

プロジェクトが育つと、便利なスクリプトを scripts/ のようなフォルダに置きたくなります。

python
# scripts/run.py
import tenki
print(tenki.fetch("Nagoya"))

ところが、tenki-app で実行するとこうなります(実際の出力です)。

$ python3 scripts/run.py
ModuleNotFoundError: No module named 'tenki'

tenki-app にいて、tenki/ はすぐ隣にあるのに見つかりません。原因は第8章の名簿です。名簿の0段目は「今いるフォルダ」ではなく「起動したスクリプトのあるフォルダ」でした。python3 scripts/run.py では0段目が tenki-app/scripts/ になり、tenki-app/ は名簿のどこにも入っていません。

起動のしかた0段目tenki は
python3 main.py(tenki-app で)tenki-app/見つかる
python3 scripts/run.py(tenki-app で)tenki-app/scripts/見つからない
python3 -m scripts.run(tenki-app で)tenki-app/(今いる場所)見つかる

-m で名前として起動すると、0段目が今いるフォルダになるので動きます。Node なら require("../tenki") と相対パスで書けば済む場面ですが、Python ではこうした「起動のしかた」が効いてきます。

sys.path.append("..") のように名簿を書き換えて逃げるコードも見かけますが、起動する場所が変わるとまた壊れます。根本的な解決は、tenki をインストールして site-packages から見えるようにすることです。それが次の src レイアウトの考え方です。

  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 18 / 22
  • よくある事故:別のフォルダのスクリプトから import できない
  • フォルダ
  • tenki-app/
  • # scripts/run.py
  • フォルダ
  • tenki/
  • import tenki
  • フォルダ
  • scripts/
  • ← sys.path[0] はここ
  • $ python3 scripts/run.py
  • 書類
  • ModuleNotFoundError: No module named 'tenki'
  • run.py
  • $ python3 -m scripts.run
  • tenki/__init__.py を実行 …
  • python3 scripts/run.py では0段目が scripts/ になり、tenki/ は名簿のどこにも無い
  • -m で名前で起動すれば0段目は今いる tenki-app。根本的には tenki を「入れる」のが正解(src レイアウト・第14章)
  • ひらめき
  • sys.path[0] は「今いる場所」ではなく「起動したスクリプトのあるフォルダ」。

src レイアウト:パッケージを src/ の中に1段下げる

今よく勧められるのが、パッケージを src/ フォルダの中に置く src レイアウトです。uv で uv init --package --name tenki と打つと、最初からこの形で作られます(実際に作ったものです)。

tenki-app/
├── pyproject.toml
├── README.md
└── src/
    └── tenki/
        └── __init__.py

packaging.python.org の説明によると、この形の狙いは「開発中のコピーをうっかり import しない」ことです。tenki-app で何かを起動しても、0段目の tenki-app には tenki/ が無い(src/ の中にある)ので、名簿からは見えません。tenki を使うには、インストールする必要があります。すると、配る前の段階から「利用者が入れたときと同じ条件」で試せます。

でも、開発中に毎回インストールし直すのは面倒です。そこで、開発中は「実物はあっち」と書いた小さなファイルだけを site-packages に置きます。uv run は、これを自動でやってくれます。

$ uv run python -c 'import tenki; print(tenki.__file__)'
/Users/you/tenki-app/src/tenki/__init__.py
$ cat .venv/lib/python3.13/site-packages/tenki.pth
/Users/you/tenki-app/src

.pth は、起動時に site モジュールが読むファイルで、書かれたフォルダを名簿の最後に付け足します。これで src/ が名簿に入り、tenki が見つかります。この仕組み(編集可能インストール)は第14章でくわしく扱います。

レイアウトtenki の場所使う条件
フラットtenki-app/tenki/0段目が tenki-app なら見つかる
srctenki-app/src/tenki/インストールすると見つかる
  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 19 / 22
  • src レイアウト:パッケージを src/ の中に1段下げる
  • フォルダ
  • tenki-app/
  • $ uv init --package --name tenki # src/ の形で作られる
  • ファイル
  • pyproject.toml
  • $ uv run python -c 'import tenki; print(tenki.__file__)'
  • /Users/you/tenki-app/src/tenki/__init__.py
  • フォルダ
  • src/
  • $ cat .venv/lib/python3.13/site-packages/tenki.pth
  • フォルダ
  • tenki/
  • /Users/you/tenki-app/src
  • 書類
  • __init__.py
  • 書類
  • api.py …
  • src/ に入れると
  • フォルダ
  • tests/
  • 良いこと
  • インストールした物と同じ条件で試せる
  • フォルダ
  • .venv/…/site-packages/
  • 必要なこと
  • 開発中も「入れる」(uv run が自動でやる)
  • ファイル
  • tenki.pth
  • 入れ方の中身
  • .pth で名簿の最後に src を足す(第14章)
  • ひらめき
  • src/ に入れると0段目から見えなくなる。「入れた」tenki だけが import され、本番と同じ条件で試せる。

JS と比べる:index.js と __init__.py

ここまでを、JS(Node)と並べます。

JS(Node)Python
フォルダを読み込むrequire("./tenki") で tenki/index.jsimport tenki で tenki/__init__.py
中のファイルrequire("./tenki/api")import tenki.api
同じフォルダの仲間import … from "./api.js"from . import api
1つ上import … from "../x.js"from .. import x
相対の基準書いたファイルの場所モジュールが属するパッケージ
区切り/(パスそのもの).(点)
外に見せる物package.json の main・exports、index.js の export__init__.py に並べる
目印が無いフォルダただのフォルダ名前空間パッケージとして import できてしまう

いちばん近いのは index.js と `__init__.py` です。どちらも「フォルダを1つの部品として読み込んだときの入口」で、よく使う物を表に並べる場所です。

違いもあります。Node の CommonJS では、require("./tenki") と書くと tenki/index.js が自動で探されますが、ESM ではフォルダ名だけの import が自動で index.js にはならず、ファイル名まで書く必要があります。Python の __init__.py は、どの書き方で import しても必ず実行されます。

もう1つは、自分のパッケージのいちばん上の名前(tenki)は、相対パスではなく名簿から探されることです。Node では自分のフォルダを ./ で指せますが、Python ではパッケージの外から tenki を指すには、tenki が名簿のどこかから見えている必要があります。「どこから起動するか」「インストールするか」が大事になるのはそのためです。

  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 20 / 22
  • JS と比べる:index.js と __init__.py
  • JS(Node)
  • Python
  • フォルダを読み込む
  • require("./tenki") → tenki/index.js
  • import tenki → tenki/__init__.py
  • 中のファイル
  • require("./tenki/api")
  • import tenki.api
  • 同じフォルダの仲間
  • import … from "./api.js"
  • from . import api
  • 1つ上
  • import … from "../x.js"
  • from .. import x
  • 相対の基準
  • 書いたファイルの場所
  • モジュールが属するパッケージ
  • 区切り
  • /(パスそのもの)
  • .(点)
  • 外に見せる物の指定
  • package.json の main / exports
  • __init__.py に並べる
  • ESM では、フォルダ名だけの import が自動で index.js にはならない(拡張子まで書く)。Python の __init__.py は、いつでも自動で実行される
  • ひらめき
  • Node のフォルダ読み込み(index.js)に近いのが __init__.py。区切りは / ではなく点。

import でつまずいたときの原因の地図

パッケージが絡んだ import のエラーを、表にまとめます。どれも「名簿(sys.path・__path__)」「フォルダの形」「起動のしかた」のどれかに原因があります。

エラーよくある原因直し方
ModuleNotFoundError: No module named 'tenki'別のフォルダのスクリプトから起動したtenki-app で python3 -m で起動する・インストールする
ModuleNotFoundError: No module named 'tenki.xyz'ファイル名の打ち間違い・置き場所の違いフォルダの木と点の名前を見比べる
ImportError: attempted relative import with no known parent packageパッケージの中のファイルを直接実行したpython3 -m tenki.display
ImportError: cannot import name 'fetch' from 'tenki'その名前がモジュールに無い__init__.py に並べたか確かめる
… from partially initialized module …(circular import)2つのファイルが互いに import し合っている共通の部分を別のファイルに出す
思ったのと違うファイルが動く同じ名前のファイルがある・古いモジュールが残っている__file__ を見る・起動し直す

最後から2番目の循環 import は、深さ優先の動きを思い出すと理解できます。a.py の途中で b.py を import し、b.py が a を import すると、a はまだ途中までしか実行されていない(棚にはあるが、中身が揃っていない)ので、「途中までしか初期化されていないモジュールから、その名前は取れない」と言われます。

困ったときは、同じ python で次の3つを出すと、ほとんどの原因が見えます。

python
import sys
print(sys.path)            # 名簿
import tenki
print(tenki.__file__)      # 実際に見つかったファイル
print(tenki.__path__)      # パッケージの中の名簿
  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 21 / 22
  • import でつまずいたときの原因の地図
  • エラー
  • よくある原因
  • 直し方
  • ModuleNotFoundError: 'tenki'
  • 別のフォルダのスクリプトから起動
  • tenki-app で python -m で起動
  • ModuleNotFoundError: 'tenki.xyz'
  • ファイル名の打ち間違い・場所違い
  • フォルダの木と点を見比べる
  • ImportError: attempted relative …
  • パッケージ内のファイルを直接実行
  • python -m tenki.display
  • ImportError: cannot import name
  • その名前がモジュールに無い
  • __init__.py に並べたか確かめる
  • partially initialized module
  • 2つのファイルが互いに import
  • 共通部分を別のファイルに出す
  • 思ったのと違う物が動く
  • 同じ名前のファイル・古い棚
  • __file__ を見る・起動し直す
  • ひらめき
  • エラーの種類で、見る場所が決まる。どれも「名簿」「フォルダの形」「起動のしかた」のどれか。

まとめ:パッケージは「__init__.py の入ったフォルダ」

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

用語意味
パッケージ__init__.py の入ったフォルダ。import するとその __init__.py が実行される
import a.b.ca/b/c.py(か a/b/c/)。左の親から順にすべて実行される
__path__パッケージの中を探すときの小さな名簿(そのフォルダ)
from . / from ..同じパッケージ / 1つ上。パッケージの中でだけ使える
python -m名前で起動する。パッケージなら __main__.py が入口
名前空間パッケージ__init__.py の無いフォルダ。特殊な用途向け
src レイアウトsrc/ に入れ、インストールした物だけを import させる形
JS との対応index.js ≒ __init__.py、/ ≒ .

そして、json も requests も、あなたの tenki/ とまったく同じ形のパッケージでした。

置き場名簿の段
tenkitenki-app/tenki/0
json…/lib/python3.13/json/2
requests…/.venv/lib/python3.13/site-packages/requests/4

では、requests のように「誰かが書いて配ったパッケージ」を、なぜライブラリと呼ぶのでしょうか。FastAPI や Django は「フレームワーク」と呼ばれますが、何が違うのでしょうか。次の第10章「ライブラリとフレームワーク」で整理します。

  • JS から来た人の Python 09 ― パッケージとフォルダ構成
  • 22 / 22
  • まとめ:パッケージは「__init__.py の入ったフォルダ」
  • 用語
  • 意味
  • パッケージ
  • __init__.py の入ったフォルダ。import するとその __init__.py が実行される
  • import a.b.c
  • a/b/c.py(か a/b/c/)。親から順にすべて実行される
  • __path__
  • パッケージの中を探すときの小さな名簿(=そのフォルダ)
  • from . / from ..
  • 同じパッケージ / 1つ上。パッケージの中でだけ使える
  • python -m
  • 名前で起動。パッケージなら __main__.py が入口
  • src レイアウト
  • src/ に入れ、入れた物だけを import させる形
  • JS との対応
  • index.js ≒ __init__.py、「/」≒「.」
  • ひらめき
  • 次の章:json も requests も「誰かが書いたパッケージ」。ではライブラリとフレームワークの違いは?

0 件のコメント

読み込み中…

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