タイトル: モジュール
SEOタイトル: Python モジュール (import) 完全ガイド(パッケージ / __init__.py / 相対 import)
| この記事の要点 |
|
import の基本
# 1. モジュール全体を import
import math
print(math.pi) # 3.141592...
# 2. 特定の名前を import
from datetime import datetime, timedelta
now = datetime.now()
tomorrow = now + timedelta(days=1)
# 3. すべて import(非推奨)
from math import * # ★ 名前空間汚染。避けるべき
# 4. 別名(エイリアス)
import numpy as np
import pandas as pd
from collections import defaultdict as dd
モジュールとパッケージ
| 概念 | 実体 | 例 |
|---|---|---|
| モジュール (Module) | 単一の .py ファイル | math.py |
| パッケージ (Package) | __init__.py 付きディレクトリ | requests/ |
| サブパッケージ | パッケージ内のパッケージ | requests/auth/ |
| 名前空間パッケージ | __init__.py 不要(Python 3.3+) | 分散したディレクトリ |
典型的なパッケージ構造
myproject/
├── __init__.py # パッケージ初期化(空でも可)
├── main.py
├── utils/
│ ├── __init__.py
│ ├── strings.py
│ └── dates.py
└── models/
├── __init__.py
├── user.py
└── order.py# main.py から各モジュールを呼ぶ
from myproject.utils.strings import slugify
from myproject.models.user import User
from myproject.models import order # サブモジュール
u = User("taro")
o = order.Order(u)
print(slugify("Hello World")) # hello-world
__init__.py の役割
# myproject/utils/__init__.py
"""utils パッケージの公開 API を集約"""
from .strings import slugify, escape_html
from .dates import format_date, parse_iso
__all__ = ["slugify", "escape_html", "format_date", "parse_iso"]
# from myproject.utils import * で出てくる名前を制限
これにより外部からは from myproject.utils import slugify という短い形で書けるようになります。
暗黙名前空間パッケージ (PEP 420, Python 3.3+)
# __init__.py が無くてもパッケージとして認識される
myns/
├── plugin1/
│ └── feature.py
└── plugin2/
└── feature.py
# 異なる場所にあるディレクトリを 1 つのパッケージとして扱える
# プラグインシステム等に便利
__name__ == "__main__" イディオム
# utils.py
def greet(name):
return f"Hello, {name}!"
if __name__ == "__main__":
# このファイルを直接 python utils.py で実行したときだけ走る
# import utils したときは走らない
print(greet("World"))
# 動作:
# $ python utils.py → "Hello, World!" 出力
# >>> import utils → 何も出力しない
相対 import と絶対 import
# myproject/models/user.py から utils.strings を参照する場合
# 絶対 import(推奨)
from myproject.utils.strings import slugify
# 相対 import (.., . で階層を表す)
from ..utils.strings import slugify # 2 階層上
from .order import Order # 同じ models パッケージ内
# 相対 import の制約:
# - パッケージ内でしか使えない
# - python myproject/models/user.py のような直接実行では動かない
# → python -m myproject.models.user で実行する
sys.path とモジュール検索順
import sys
print(sys.path)
# ['', '/usr/lib/python311.zip', '/usr/lib/python3.11', ...]
# 先頭が空文字 = カレントディレクトリ
# import 時は sys.path を順に探す
# 1. 組み込みモジュール (sys, builtins)
# 2. sys.path の各エントリ
# 3. 見つからなければ ModuleNotFoundError
# 動的に追加(推奨されないが緊急時に)
sys.path.insert(0, "/path/to/my/libs")
import my_lib
モジュールのキャッシュとリロード
import sys
import mymodule
# import したモジュールは sys.modules にキャッシュされる
print(sys.modules['mymodule'])
# 同じプロセス内で import しても 2 回目以降は実行されない
# 編集を反映したい場合(開発中など)
import importlib
importlib.reload(mymodule)
# キャッシュから削除して再 import
del sys.modules['mymodule']
import mymodule
標準ライブラリ主要モジュール
| カテゴリ | モジュール | 用途 |
|---|---|---|
| テキスト | re / string / textwrap | 正規表現 / 文字列定数 / 整形 |
| 数値 | math / random / statistics / decimal | 数学関数 / 乱数 / 統計 / 十進演算 |
| 日付 | datetime / time / calendar / zoneinfo | 日時 / Unix 時間 / タイムゾーン (3.9+) |
| データ構造 | collections / heapq / bisect / queue | defaultdict / deque / ヒープ / キュー |
| 関数 | functools / itertools / operator | lru_cache / 組合せ / 演算子 |
| ファイル | os / pathlib / shutil / glob | パス操作 / コピー / パターン検索 |
| I/O | io / json / csv / pickle | ストリーム / 各種フォーマット |
| 並行 | threading / multiprocessing / asyncio / concurrent.futures | スレッド / プロセス / 非同期 |
| HTTP | urllib / http | 標準 HTTP クライアント(実用は requests) |
| テスト | unittest / doctest | テスト基盤(実用は pytest) |
サードパーティパッケージのインストール
# pip でインストール
pip install requests pandas
# 仮想環境を作って分離(推奨)
python -m venv .venv
source .venv/bin/activate # Mac/Linux
.venv\Scripts\activate # Windows
pip install -r requirements.txt
# pyproject.toml / Poetry を使う場合
poetry add requests
poetry install
モジュールから他の属性を取得
import math
# 公開属性一覧
print(dir(math))
# ['__doc__', '__name__', ..., 'pi', 'sqrt', 'sin', ...]
# ドキュメント
help(math.sqrt)
print(math.sqrt.__doc__)
# 属性が存在するか
print(hasattr(math, 'pi')) # True
# 動的取得
fn = getattr(math, 'sqrt')
print(fn(16)) # 4.0
FAQ
Q: from x import * はなぜダメ?
A: 名前空間が汚染され、どの関数がどこから来たか不明になります。__all__ 制限があっても可読性が落ちるため避けるべき。
Q: 循環 import が起きた
A: A が B を、B が A を import する状態。回避策は (1) 関数内で遅延 import、(2) 共通部分を 3 つ目のモジュールに分離、(3) 設計見直し(依存方向を一方向に)。
Q: スクリプトをパッケージ内で実行したい
A: python -m myproject.models.user を使えば相対 import も動きます。python myproject/models/user.py はパッケージ認識されない。