- Python
Python importの使い方|自作モジュールとエラー対処
Pythonの import とは、別のファイル(モジュール)やフォルダ(パッケージ)に書かれた関数・クラス・変数を、自分のコードから使えるようにする文です。 標準ライブラリも、pip で入れたライブラリも、自分で書いたファイルも、同じ import 文で読み込みます。
書き方そのものは短いのですが、自作のファイルを読み込もうとすると ModuleNotFoundError や attempted relative import に出会うことがよくあります。原因のほとんどは「Python がどのフォルダを探しているか(sys.path)」と「どうやって実行したか」の 2 点に集約されます。
この記事では、import 構文の一覧表、フォルダ構成図つきの自作モジュール・パッケージの作り方、そして代表的なエラーの再現と原因別の解決手順を、すべて手元で実行した結果つきで紹介します。検証は Python 3.11.15、一部のエラーメッセージの比較に Python 3.14.7 を使いました。出力中のパスは /home/user/... に置き換えています。
importの早見表
構文の一覧
| 書き方 | 意味 | 使うときの書き方 |
|---|---|---|
import calc |
モジュール全体を読み込む | calc.add_tax(100) |
import calc as c |
別名を付けて読み込む | c.add_tax(100) |
from calc import add_tax |
中の名前を直接読み込む | add_tax(100) |
from calc import add_tax, TAX_RATE |
複数の名前を読み込む | add_tax(100)、TAX_RATE |
from calc import add_tax as tax |
名前に別名を付ける | tax(100) |
from calc import * |
公開されている名前をすべて読み込む | add_tax(100)(由来が見えにくくなる) |
import app.utils.money |
パッケージ内のモジュールを読み込む | app.utils.money.add_tax(100) |
from app.utils import money |
パッケージからモジュールを読み込む | money.add_tax(100) |
from . import item |
相対 import:同じパッケージ内のモジュール | item.Item(...) |
from .item import Item |
相対 import:同じフォルダのモジュールの中身 | Item(...) |
from ..utils.money import add_tax |
相対 import:1 つ上のパッケージから | add_tax(100) |
importlib.import_module("app.utils.money") |
文字列で指定して読み込む | 戻り値のモジュールを使う |
エラーから原因を引く表
| エラー文(一部) | 主な原因 | まず試すこと |
|---|---|---|
ModuleNotFoundError: No module named 'app' |
探す場所(sys.path)にそのフォルダがない | ルートのフォルダで python -m を使って実行 |
ModuleNotFoundError: No module named 'requests' |
その Python にインストールされていない | python -m pip install requests |
ImportError: attempted relative import with no known parent package |
相対 import を含むファイルを直接実行した | python -m パッケージ.モジュール で実行 |
ImportError: attempted relative import beyond top-level package |
.. がパッケージの最上位を越えた |
ドットの数、実行する場所を見直す |
ImportError: cannot import name 'X' from partially initialized module |
循環 import | import を関数の中へ移す、共通部分を別ファイルへ |
ImportError: cannot import name 'X' from 'calc' |
名前のつづり違い、その名前が定義されていない | モジュール側の定義を確認 |
AttributeError: module 'random' has no attribute ... |
標準ライブラリと同名の自作ファイルがある | 自作ファイルの名前を変える |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Python importの使い方|自作モジュールとエラー対処」
基本の使い方:自作モジュールを import する
モジュールとは、.py ファイル 1 つのことです。 ファイル名から .py を取ったものがモジュール名になります。まずは同じフォルダに 2 つのファイルを置く、いちばん単純な形から始めます。
shop/
├── calc.py ← 自作モジュール
└── main.py ← 実行するファイル
calc.py:
TAX_RATE = 0.1
def add_tax(price):
return int(price * (1 + TAX_RATE))
def _round(x):
return round(x)
if __name__ == "__main__":
print("calc.py を直接実行:", add_tax(1000))
main.py:
import calc
import calc as c
from calc import add_tax
from calc import add_tax as tax, TAX_RATE
print(calc.add_tax(1000))
print(c.TAX_RATE)
print(add_tax(200), tax(300), TAX_RATE)
print(calc.__name__, __name__)
cd shop
python3 main.py
実行結果:
1100
0.1
220 330 0.1
calc __main__
4 つの書き方はどれも同じ calc.py を読み込んでいます。違いは「どの名前で使えるようになるか」だけです。
import と from の使い分け
| 書き方 | 長所 | 気を付ける点 | 向いている場面 |
|---|---|---|---|
import calc |
calc.add_tax と書くので、どこの関数か一目でわかる |
毎回モジュール名を書く | 基本はこれ |
import numpy as np |
長い名前を短くできる | 独自の略し方は読み手が迷う | 慣習の別名があるライブラリ |
from calc import add_tax |
短く書ける | 同じ名前の変数を作ると上書きされる | 何度も使う少数の名前 |
from calc import * |
一度に全部使える | どの名前がどこから来たか追いにくい | 対話モードでの試し書き |
迷ったら import モジュール名、頻繁に使うものだけ from ... import 名前 とすると、読みやすさと書きやすさのバランスが取れます。
import は最初の 1 回だけ実行される
同じモジュールを何度 import しても、ファイルの中身が実行されるのは最初の 1 回だけです。読み込んだモジュールは sys.modules という辞書に記録され、2 回目以降はそこから取り出されます。
import calc, sys
import calc
print(calc.__name__, 'calc' in sys.modules, calc.__file__)
calc True /home/user/shop/calc.py
モジュール.__file__ を表示すると、実際にどのファイルが読み込まれたかがわかります。 意図しないファイルを読んでいないか調べるときの、いちばん確実な方法です。対話モードでファイルを書き換えたあとに読み直したいときは importlib.reload(calc) を使います。
if __name__ == "__main__" の意味
先ほどの出力の最後の行は calc __main__ でした。__name__ は、そのファイルが「どう読み込まれたか」を表す変数です。
| 読み込まれ方 | __name__ の値 |
|---|---|
python3 calc.py と直接実行された |
"__main__" |
import calc で読み込まれた |
"calc"(モジュール名) |
python3 -m app.cli で実行された |
"__main__" |
この仕組みを使うと、「直接実行されたときだけ動かす処理」を書けます。
python3 calc.py
calc.py を直接実行: 1100
main.py から import したときには、この行は表示されませんでした。import される側のファイルでは、関数とクラスの定義だけをトップレベルに置き、動作確認や起動の処理は if __name__ == "__main__": の中に入れると、import しただけで処理が走ることを防げます。
パッケージを作る:フォルダで整理する
ファイルが増えてきたら、フォルダに分けて整理します。モジュールを入れたフォルダを「パッケージ」と呼びます。
shop/ ← ルート(ここで実行する)
├── run.py
├── app/
│ ├── __init__.py
│ ├── cli.py
│ ├── models/
│ │ ├── __init__.py
│ │ ├── item.py
│ │ └── order.py
│ └── utils/
│ ├── __init__.py
│ └── money.py
└── scripts/
└── report.py
app/__init__.py(動きを見るために print を入れています):
print("app/__init__.py が実行されました")
app/utils/money.py(app/utils/__init__.py は空のファイル):
def add_tax(price, rate=0.1):
return int(price * (1 + rate))
app/models/item.py:
class Item:
def __init__(self, name, price):
self.name = name
self.price = price
app/models/order.py(相対 import を使用):
from .item import Item
from ..utils.money import add_tax
class Order:
def __init__(self):
self.items: list[Item] = []
def add(self, item: Item):
self.items.append(item)
def total(self):
return add_tax(sum(i.price for i in self.items))
app/models/__init__.py:
from .item import Item
from .order import Order
__all__ = ["Item", "Order"]
run.py:
from app.models import Item, Order
order = Order()
order.add(Item("ノート", 300))
order.add(Item("ペン", 120))
print("合計:", order.total())
cd shop
python3 run.py
app/__init__.py が実行されました
合計: 462
__init__.py の役割
__init__.py は、そのフォルダが import されたときに最初に実行されるファイルです。 上の結果でも、from app.models import ... と書いただけで app/__init__.py が実行されています。
| 役割 | 例 |
|---|---|
| フォルダを通常のパッケージとして示す | 空のファイルを置く |
| 中の名前を引き上げて、短く import できるようにする | from .item import Item と書くと from app.models import Item で使える |
from パッケージ import * の対象を決める |
__all__ = ["Item", "Order"] |
| パッケージの初期化 | バージョン番号の定義など(重い処理は入れないのがおすすめ) |
app/models/__init__.py で Item と Order を引き上げているので、使う側は from app.models.item import Item と奥まで書かずに、from app.models import Item と短く書けます。
絶対 import と相対 import
パッケージの中から別のモジュールを読み込む書き方は 2 種類あります。
| 種類 | 書き方(app/models/order.py の中で) |
特徴 |
|---|---|---|
| 絶対 import | from app.models.item import Item |
ルートからの完全な名前。場所がひと目でわかる |
| 相対 import | from .item import Item |
自分の位置からの相対。パッケージ名を変えても書き換え不要 |
相対 import のドットは、フォルダの . .. と同じ感覚で読めます。
| 書き方 | 指す場所(app/models/order.py から見て) |
|---|---|
from . import item |
同じパッケージ app/models/ の item.py |
from .item import Item |
同じパッケージの item.py の中の Item |
from .. import utils |
1 つ上のパッケージ app/ の utils |
from ..utils.money import add_tax |
app/utils/money.py の中の add_tax |
相対 import は from で始まる形だけで、import .item とは書けません。PEP 8 では絶対 import を基本とし、パッケージ内部の込み入った構成では相対 import も使ってよい、としています。チームでどちらかに決めておくと読みやすくなります。
__init__.py がないフォルダ:名前空間パッケージ
Python 3.3 以降は、__init__.py がないフォルダも import できます。これを名前空間パッケージと呼びます。手元で、__init__.py のない nsdemo/ フォルダと、ある app/ フォルダを比べました。
import nsdemo, nsdemo.mod
print(nsdemo, nsdemo.mod.X)
import app
print(app)
<module 'nsdemo' (<_frozen_importlib_external.NamespaceLoader object at 0x7f7cab70ce50>)> 1
app/__init__.py が実行されました
<module 'app' from '/home/user/shop/app/__init__.py'>
名前空間パッケージは、別々の場所にある同じ名前のフォルダを 1 つのパッケージとして合成できるのが本来の用途です。part1/acme/tools/ と part2/acme/docs/ を両方 sys.path に入れて確認しました。
import acme, acme.tools, acme.docs
print(acme.tools.NAME, acme.docs.NAME)
print(acme.__file__)
print(acme.__path__)
tools docs
None
_NamespacePath(['/home/user/ns/part1/acme', '/home/user/ns/part2/acme'])
| 項目 | 通常のパッケージ | 名前空間パッケージ |
|---|---|---|
__init__.py |
あり | なし |
__file__ |
__init__.py のパス |
None |
| 初期化の処理 | 書ける | 書けない |
| 複数の場所に分割 | できない | できる |
| 向いている場面 | 通常のアプリ・ライブラリ | 複数の配布物で 1 つの名前を共有する大きなライブラリ |
ふつうのアプリでは、__init__.py を置いて通常のパッケージにするのがおすすめです。 pytest や mypy、パッケージ化のツールがフォルダを見つけやすくなり、置き忘れによる挙動の違いに悩まずに済みます。
from module import * と __all__
from モジュール import * で読み込まれる名前は、次のルールで決まります。
| モジュールの状態 | 読み込まれる名前 |
|---|---|
__all__ がない |
アンダースコア(_)で始まらない名前すべて |
__all__ がある |
__all__ のリストに書かれた名前だけ |
calc.py(__all__ なし)で確かめると、_round は除かれました。
from calc import *
print([n for n in dir() if not n.startswith('__')])
['TAX_RATE', 'add_tax']
次に、__all__ を定義した shapes.py です。
__all__ = ["area"]
PI = 3.14159
def area(r):
return PI * r * r
def perimeter(r):
return 2 * PI * r
from shapes import *
print(area(1))
print('perimeter' in dir(), 'PI' in dir())
from shapes import perimeter
print(perimeter(1))
3.14159
False False
6.28318
__all__ は import * の対象を絞るだけで、名前を指定した import は制限しません。 「このモジュールが外向けに公開している名前の一覧」を示す役割もあり、エディタの補完や静的解析ツールもこの一覧を参照します。なお、import * を関数の中に書くと SyntaxError: import * only allowed at module level になります。
Python はどこを探すのか:sys.path
import のエラーを理解するいちばんの近道は、sys.path(モジュールを探すフォルダのリスト) を知ることです。Python は import 文に出会うと、このリストを先頭から順に探し、最初に見つかったものを読み込みます。
showpath.py:
import sys
for p in sys.path:
print(repr(p))
cd shop
python3 showpath.py
'/home/user/shop'
'/usr/lib/python311.zip'
'/usr/lib/python3.11'
'/usr/lib/python3.11/lib-dynload'
'/root/.local/lib/python3.11/site-packages'
'/usr/local/lib/python3.11/dist-packages'
'/usr/lib/python3/dist-packages'
| 順番 | 中身 | 由来 |
|---|---|---|
| 先頭 | 実行したスクリプトがあるフォルダ | 実行方法で決まる |
| 次 | 環境変数 PYTHONPATH のフォルダ |
設定したときだけ |
| その次 | 標準ライブラリ | Python 本体 |
| 最後 | site-packages(pip で入れたライブラリ) | venv ならその venv の中 |
大事なのは先頭の 1 行が、実行方法によって変わることです。
| 実行方法 | sys.path の先頭 |
|---|---|
python3 scripts/report.py |
スクリプトのあるフォルダ(shop/scripts) |
python3 -m scripts.report |
コマンドを実行したフォルダ(カレントディレクトリ) |
python3 -c "..."・対話モード |
空文字 ''(カレントディレクトリの意味) |
「カレントディレクトリが探される」と思いがちですが、ファイルを直接実行したときに探されるのは、そのファイルが置かれたフォルダです。 この違いが、次の章のエラーの原因になります。
エラーの再現と解決
ModuleNotFoundError: No module named 'app'(実行場所と sys.path)
scripts/report.py から app パッケージを使おうとした例です。
import sys
print("sys.path[0] =", sys.path[0])
from app.models import Item
print(Item("消しゴム", 80).name)
cd shop
python3 scripts/report.py
sys.path[0] = /home/user/shop/scripts
Traceback (most recent call last):
File "/home/user/shop/scripts/report.py", line 3, in <module>
from app.models import Item
ModuleNotFoundError: No module named 'app'
shop/ で実行しているのに、app が見つかりません。sys.path の先頭が shop/scripts になっていて、その中に app フォルダがないからです。解決の方法は 3 つあり、どれも手元で動作を確認しました。
解決 1:python -m で実行する
cd shop
python3 -m scripts.report
sys.path[0] = /home/user/shop
app/__init__.py が実行されました
消しゴム
-m は「モジュール名を指定して実行する」オプションです。カレントディレクトリが sys.path の先頭に入るので、ルートのフォルダで実行すれば app が見つかります。指定はファイルのパスではなく、.py を付けないドット区切りの名前です。
解決 2:PYTHONPATH でルートを追加する
cd shop
PYTHONPATH=. python3 scripts/report.py
sys.path[0] = /home/user/shop/scripts
app/__init__.py が実行されました
消しゴム
Windows の PowerShell では $env:PYTHONPATH = "." を先に実行します。
解決 3:pip install -e . でパッケージとして登録する
ルートに pyproject.toml を置き、編集可能インストールをすると、どのフォルダから実行しても import できるようになります。
[build-system]
requires = ["setuptools>=77"]
build-backend = "setuptools.build_meta"
[project]
name = "shop-app"
version = "0.1.0"
requires-python = ">=3.10"
[tool.setuptools.packages.find]
include = ["app*"]
cd shop
python -m pip install -e . # venv を有効化した状態で
cd /tmp
python /home/user/shop/scripts/report.py
sys.path[0] = /home/user/shop/scripts
app/__init__.py が実行されました
消しゴム
pip list には shop-app 0.1.0 /home/user/shop と、元のフォルダの場所つきで表示されました。pip のコマンドの詳細は別記事「pipコマンド一覧」にまとめています。
| 方法 | 手軽さ | 効果の範囲 | 向いている場面 |
|---|---|---|---|
python -m で実行 |
設定なし | そのコマンドだけ | まず試す。日常の実行 |
PYTHONPATH |
環境変数を設定 | そのシェル・その設定 | Docker や CI の設定 |
pip install -e . |
pyproject.toml が必要 | その venv 全体 | テストやツールからも使う、長く育てるコード |
sys.path.append(...) をコードに書く |
1 行で済む | そのファイル | 使い捨ての検証(コードが環境に依存するため、常用は上の 3 つがおすすめ) |
ImportError: attempted relative import with no known parent package
相対 import を含むファイルを、直接実行したときのエラーです。app/cli.py を用意しました。
from .models import Item, Order
def main():
order = Order()
order.add(Item("付箋", 200))
print("合計:", order.total())
if __name__ == "__main__":
main()
cd shop
python3 app/cli.py
Traceback (most recent call last):
File "/home/user/shop/app/cli.py", line 1, in <module>
from .models import Item, Order
ImportError: attempted relative import with no known parent package
直接実行されたファイルは __main__ という名前の単独のモジュールとして扱われ、「自分がどのパッケージに属しているか」の情報を持ちません。 そのため、.(自分のパッケージ)を解決できずに止まります。
解決は、ルートのフォルダから -m で実行することです。
cd shop
python3 -m app.cli
app/__init__.py が実行されました
合計: 220
| 直す前 | 直した後 |
|---|---|
python3 app/cli.py |
python3 -m app.cli |
cd app && python3 cli.py |
cd shop && python3 -m app.cli |
-m で実行すると、Python は app.cli がパッケージ app の一員であることを把握するので、相対 import が解決されます。VS Code などのエディタの実行ボタンは「ファイルを直接実行」する設定になっていることが多いので、実行構成で「モジュールとして実行」を選ぶと同じ結果になります。
似たエラーに attempted relative import beyond top-level package があります。これは、.. の数が多く、パッケージの最上位を越えたときに出ます。app/utils/ の中のファイルに from ....x import y と書いて import すると、手元でも次のように表示されました。
ImportError: attempted relative import beyond top-level package
ドットの数を数え直すか、絶対 import(from app.xxx import ...)に書き換えると解決します。
circular import(循環 import)
2 つのモジュールがお互いを import し合うと起こります。
member.py:
from team import Team
class Member:
def __init__(self, name):
self.name = name
def team(self):
return Team("開発")
team.py:
from member import Member
class Team:
def __init__(self, name):
self.name = name
self.members = [Member("佐藤")]
python3 -c "import member"
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/home/user/circ/member.py", line 1, in <module>
from team import Team
File "/home/user/circ/team.py", line 1, in <module>
from member import Member
ImportError: cannot import name 'Member' from partially initialized module 'member' (most likely due to a circular import) (/home/user/circ/member.py)
起きていることを順に追うと、次のとおりです。
sequenceDiagram
participant P as Python
participant M as member.py
participant T as team.py
P->>M: import member(1行目を実行)
M->>T: from team import Team
T->>M: from member import Member
Note over M: まだ1行目の途中。Member は未定義
M-->>T: ImportError(partially initialized)
partially initialized module(初期化の途中のモジュール)という言葉が、循環 import の目印です。 import team の形で読み込んで属性を使った場合は、AttributeError: partially initialized module 'member' has no attribute 'DEFAULT' (most likely due to a circular import) という形で現れました。
解決方法は次の 3 つです。
| 方法 | 内容 | 向いている場面 |
|---|---|---|
| import を関数の中へ移す | 使う時点で import する | 片方が、もう片方を一部の処理でしか使わない |
| 共通部分を別ファイルへ出す | 両方が使うものを第 3 のモジュールに移す | 根本的に整理したい |
| 型ヒント用の import を分ける | if TYPE_CHECKING: の中で import |
型注釈のためだけに必要なとき |
1 つ目の方法で member.py を直しました。
class Member:
def __init__(self, name):
self.name = name
def team(self):
from team import Team # 使う時点で import する
return Team("開発")
from member import Member
t = Member('鈴木').team()
print(t.name, [m.name for m in t.members])
開発 ['佐藤']
型ヒントのためだけに相手のクラスが必要な場合は、次の書き方が使えます(標準ライブラリの typing の機能で、公式ドキュメントで確認した書き方です)。
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from team import Team # 型チェックのときだけ読み込まれる
循環が何度も起こるときは、「2 つのモジュールの役割が重なっている」というサインでもあります。依存の向きを一方通行にする(たとえば models は utils を使うが、utils は models を使わない)と決めておくと、構成がすっきりします。
ImportError: cannot import name
モジュールは見つかったものの、その中に指定した名前がないときのエラーです。
python3 -c "from calc import add_taxx"
ImportError: cannot import name 'add_taxx' from 'calc' (/home/user/shop/calc.py)
Python 3.14.7 では、候補も表示されました。
ImportError: cannot import name 'add_taxx' from 'calc' (/home/user/shop/calc.py). Did you mean: 'add_tax'?
エラー文の末尾のかっこ内に、実際に読み込まれたファイルのパスが出ます。 ここが意図したファイルかどうかを最初に見ます。
| 原因 | 見分け方 | 対処 |
|---|---|---|
| 名前のつづり違い | モジュール側の定義と見比べる | つづりを直す |
| 別のファイルを読んでいる | かっこ内のパスが想定と違う | 同名ファイルを改名する |
| ライブラリの版が違う | その名前が追加・移動された版か確認 | pip show で版を確認し、合わせる |
| 循環 import | partially initialized と書かれている |
前の項の方法で解消 |
標準ライブラリと同名のファイル(random.py)
自作のファイルに random.py、json.py、test.py、email.py など、標準ライブラリと同じ名前を付けると、sys.path の先頭にある自作ファイルのほうが先に見つかり、標準ライブラリが読み込まれなくなります。
random.py:
import random
print(random.randint(1, 6))
python3 random.py
Python 3.11.15 の結果:
Traceback (most recent call last):
File "/home/user/shadow/random.py", line 1, in <module>
import random
File "/home/user/shadow/random.py", line 3, in <module>
print(random.randint(1, 6))
^^^^^^^^^^^^^^
AttributeError: partially initialized module 'random' has no attribute 'randint' (most likely due to a circular import)
import random が自分自身を読み込んでいるため、循環 import と同じ形のメッセージになります。Python 3.14.7 では、原因と対処がそのまま表示されました。
AttributeError: module 'random' has no attribute 'randint' (consider renaming '/home/user/shadow/random.py' since it has the same name as the standard library module named 'random' and prevents importing that standard library module)
別のファイルから読み込む形でも同じです。フォルダに json.py を置いた状態で import json すると、__file__ は自作のファイルを指していました。
/home/user/shadow/json.py ← json.py がある状態
/usr/lib/python3.11/json/__init__.py ← json.py を削除したあと
対処は、自作ファイルの名前を変えることです(例:random.py を dice.py に)。同じフォルダに __pycache__ があれば、合わせて削除しておくと確実です。「標準ライブラリの関数がないと言われる」ときは、print(モジュール.__file__) で読み込み元を確認すると、すぐに気付けます。
No module named 'requests'(pip 未導入・venv 違い)
外部ライブラリが見つからないケースです。新しく作った venv の Python と、OS の Python で比べました。
python3 -m venv ../v1
../v1/bin/python -c "import requests"
python3 -c "import requests; print(requests.__version__)"
ModuleNotFoundError: No module named 'requests'
2.34.2
同じマシンでも、Python ごとにインストール済みのライブラリは別々です。 OS の Python には入っていても、venv の Python には入っていません。「pip install したのに見つからない」ときは、インストールした先と、実行している Python がずれています。
確認の手順は次のとおりです。
python -c "import sys; print(sys.executable)" # 実行している Python
python -m pip --version # その Python の pip
python -m pip list # その Python に入っているもの
python -m pip install requests # その Python に入れる
手元の venv では、sys.executable が /home/user/v1/bin/python、pip list は pip と setuptools だけでした。pip install ではなく python -m pip install と書くと、実行に使う Python と同じ場所へ確実に入ります。
| 状況 | 確認すること | 対処 |
|---|---|---|
| そもそも入れていない | python -m pip list |
python -m pip install 名前 |
| venv を有効化していない | sys.executable が venv の中か |
source .venv/bin/activate |
| エディタが別の Python を使っている | エディタのインタープリター設定 | venv の Python を選ぶ |
| import 名とインストール名が違う | No module named 'yaml' など |
下の表の名前でインストール |
| 大文字と小文字の違い | No module named 'Calc' |
ファイル名どおりに書く |
import する名前と、pip で指定する名前が異なるライブラリの例です。
| import 文 | インストールするときの名前 |
|---|---|
import yaml |
pyyaml |
import cv2 |
opencv-python |
import PIL |
pillow |
import sklearn |
scikit-learn |
import bs4 |
beautifulsoup4 |
import dotenv |
python-dotenv |
venv の作り方・有効化のコマンドは、別記事「Python venvの使い方」で OS 別に紹介しています。
原因別チェックリスト
import のエラーが出たら、上から順に確認します。
| 順番 | 確認すること | コマンド・見る場所 |
|---|---|---|
| 1 | エラーの種類は何か | No module named/relative import/cannot import name/partially initialized |
| 2 | どの Python で動かしているか | python -c "import sys; print(sys.executable)" |
| 3 | どこを探しているか | python -c "import sys; print(sys.path)" |
| 4 | どこで・どう実行したか | ルートのフォルダで python -m パッケージ.モジュール にする |
| 5 | 実際に読まれたファイルはどれか | print(モジュール.__file__) |
| 6 | 標準ライブラリと同じ名前のファイルがないか | random.py・json.py・test.py などを改名 |
| 7 | 外部ライブラリは入っているか | python -m pip show 名前 |
| 8 | つづり・大文字小文字は合っているか | ファイル名・定義と見比べる |
| 9 | お互いに import し合っていないか | トレースバックに 2 つのファイルが交互に出ていないか |
import できるかどうかだけを調べたいときは、importlib.util.find_spec が便利です。見つかれば場所、見つからなければ None が返りました。
import importlib.util
print(importlib.util.find_spec('app.models').origin)
print(importlib.util.find_spec('nothing_here'))
/home/user/shop/app/models/__init__.py
None
import 文の書き方の作法
PEP 8(Python の公式スタイルガイド)に沿った並べ方です。
# 1. 標準ライブラリ
import json
import sys
from pathlib import Path
# 2. 外部ライブラリ
import requests
# 3. 自作のモジュール
from app.models import Item, Order
from app.utils.money import add_tax
| 作法 | 内容 |
|---|---|
| ファイルの先頭にまとめる | 循環 import の回避など、理由があるときだけ関数の中に書く |
| 3 つのグループに分け、空行で区切る | 標準 → 外部 → 自作 |
| 1 行に 1 モジュール | import os, sys ではなく 2 行に分ける(from x import a, b は 1 行でよい) |
| ワイルドカードは控えめに | 名前の由来がわかる形で書く |
| 並び順は道具に任せる | Ruff の isort ルール(I)で自動整列できる |
よくある質問
Q. __init__.py は必ず必要ですか?
A. Python 3.3 以降は、なくても import できます(名前空間パッケージ)。ただし、初期化の処理や名前の引き上げが書けず、ツールによってはフォルダの扱いが変わります。通常のアプリでは、空のファイルでよいので置いておくのがおすすめです。
Q. 1 つ上のフォルダにあるモジュールを import するには?
A. 「上のフォルダ」ではなく、「ルートのフォルダから見た名前」で考えると整理できます。ルートで python -m パッケージ.モジュール として実行すれば、どのファイルからも from app.utils.money import add_tax のように絶対 import で書けます。別のフォルダからも使いたい場合は pip install -e . で登録します。
Q. import a.b.c と from a.b import c は何が違いますか?
A. 読み込まれるものは同じで、使うときの名前が違います。前者は a.b.c.func()、後者は c.func() と書きます。import a.b.c as c と書けば、後者と同じ名前で使えます。
Q. Jupyter Notebook で自作モジュールを書き換えても反映されません。
A. import は最初の 1 回だけ実行されるためです。importlib.reload(モジュール) で読み直すか、カーネルを再起動します。IPython の %load_ext autoreload と %autoreload 2 を使うと、実行のたびに自動で読み直されます(この拡張機能は手元では実行しておらず、IPython の公式ドキュメントで確認した内容です)。
まとめ
- import の書き方は
import・from ... import・as・相対 import(...)の組み合わせ。迷ったらimport モジュール名 - Python は sys.path を先頭から探す。ファイルを直接実行すると、先頭は「そのファイルのあるフォルダ」になる
ModuleNotFoundErrorは、ルートのフォルダでpython -m パッケージ.モジュールと実行するのが最初の一手- 相対 import を含むファイルは直接実行せず、
-mで実行する partially initialized moduleは循環 import の目印。import を関数の中へ移すか、共通部分を別ファイルに出すrandom.pyなど標準ライブラリと同じ名前は避ける。モジュール.__file__で読み込み元を確認できる- 外部ライブラリは
python -m pip installで、実行する Python と同じ場所に入れる
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Python importの使い方|自作モジュールとエラー対処」
株式会社RJCでは、Python の import やパッケージ構成の考え方を、仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。