はじめに
コードを複数のファイルに分割することで、保守性と再利用性が向上します。Pythonのモジュールとパッケージの仕組みを学びましょう。
モジュールとは
1つのPythonファイル(.py)がモジュールです。
# utils.py
def greet(name):
return f"こんにちは、{name}さん!"
def add(a, b):
return a + b
PI = 3.14159
import文の使い方
モジュール全体をインポート
import utils
print(utils.greet("太郎"))
print(utils.add(1, 2))
print(utils.PI)
特定の要素だけインポート
from utils import greet, PI
print(greet("太郎"))
print(PI)
# add は使えない
別名をつける
import utils as u
from utils import greet as hello
print(u.add(1, 2))
print(hello("太郎"))
全てをインポート(非推奨)
from utils import *
# 名前空間が汚染されるため非推奨
標準ライブラリの活用
# よく使う標準ライブラリ
import os
import sys
import json
import datetime
import random
import math
import re
import collections
from pathlib import Path
# 使用例
print(os.getcwd())
print(sys.version)
print(datetime.datetime.now())
print(random.randint(1, 100))
print(math.sqrt(16))
パッケージとは
複数のモジュールをディレクトリにまとめたものがパッケージです。
mypackage/
├── __init__.py
├── utils.py
├── models.py
└── subpackage/
├── __init__.py
└── helpers.py
__init__.pyの役割
パッケージであることを示すファイルです(Python 3.3以降は省略可能だが、推奨)。
# mypackage/__init__.py
from .utils import greet
from .models import User
__all__ = ["greet", "User"] # from mypackage import * で公開するもの
パッケージのインポート
# パッケージからインポート
from mypackage import greet
from mypackage.models import User
from mypackage.subpackage.helpers import helper_func
# 相対インポート(パッケージ内で使用)
# models.py から
from .utils import greet
from ..other_package import something
パッケージの作成例
calculator/
├── __init__.py
├── basic.py
└── advanced.py
# calculator/basic.py
def add(a, b):
return a + b
def subtract(a, b):
return a - b
# calculator/advanced.py
import math
def power(base, exp):
return base ** exp
def sqrt(n):
return math.sqrt(n)
# calculator/__init__.py
from .basic import add, subtract
from .advanced import power, sqrt
__version__ = "1.0.0"
# 使用側
from calculator import add, sqrt
print(add(1, 2))
print(sqrt(16))
import calculator
print(calculator.__version__)
if __name__ == "__main__"
スクリプトとして実行された場合のみ動作するコードを記述します。
# utils.py
def greet(name):
return f"こんにちは、{name}さん!"
def main():
print(greet("テスト"))
if __name__ == "__main__":
# python utils.py で実行した場合のみ動作
main()
モジュール検索パス
Pythonは以下の順序でモジュールを検索します。
import sys
print(sys.path)
# ['', '/usr/lib/python3.x', ...]
# パスを追加
sys.path.append('/path/to/modules')
環境変数PYTHONPATHでも設定可能です。
仮想環境
プロジェクトごとに依存関係を分離します。
# 仮想環境の作成
python -m venv venv
# 有効化
# Windows
venv\Scripts\activate
# macOS/Linux
source venv/bin/activate
# パッケージのインストール
pip install requests
# 依存関係の書き出し
pip freeze > requirements.txt
# 依存関係のインストール
pip install -r requirements.txt
# 無効化
deactivate
実践的なプロジェクト構成
my_project/
├── src/
│ └── my_project/
│ ├── __init__.py
│ ├── main.py
│ ├── models/
│ │ ├── __init__.py
│ │ └── user.py
│ └── utils/
│ ├── __init__.py
│ └── helpers.py
├── tests/
│ ├── __init__.py
│ └── test_main.py
├── requirements.txt
├── setup.py
└── README.md
# src/my_project/models/user.py
class User:
def __init__(self, name, email):
self.name = name
self.email = email
# src/my_project/models/__init__.py
from .user import User
pyproject.toml(モダンな設定)
[project]
name = "my_project"
version = "0.1.0"
description = "My awesome project"
requires-python = ">=3.9"
dependencies = [
"requests>=2.28.0",
]
[project.optional-dependencies]
dev = [
"pytest>=7.0.0",
"black>=23.0.0",
]
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
実践例:設定管理モジュール
# config/__init__.py
import os
import json
from pathlib import Path
class Config:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance._load()
return cls._instance
def _load(self):
config_path = Path(__file__).parent / "settings.json"
if config_path.exists():
with open(config_path) as f:
self._data = json.load(f)
else:
self._data = {}
# 環境変数で上書き
self._data["debug"] = os.getenv("DEBUG", "false").lower() == "true"
self._data["database_url"] = os.getenv("DATABASE_URL", self._data.get("database_url"))
def get(self, key, default=None):
return self._data.get(key, default)
# シングルトンとして使用
config = Config()
# 使用側
from config import config
if config.get("debug"):
print("デバッグモード")
まとめ
- モジュール = 1つの
.pyファイル - パッケージ = ディレクトリにまとめたモジュール群
__init__.pyでパッケージの公開APIを定義if __name__ == "__main__"でスクリプト実行時の処理を分離- 仮想環境でプロジェクトごとに依存関係を管理
pyproject.tomlでモダンなパッケージ設定
次回は仮想環境と依存関係管理について詳しく学びます。