業務で「ちょっと自動化したい」場面は多いのに、作ったスクリプトがすぐ壊れたり、別の仕事で使い回せなかったりして疲れていませんか?本記事は、実務で使える「読みやすく、再利用でき、運用しやすい」Pythonスクリプトの設計とテンプレートを、現場目線で整理します。まずは小さな改善から始められるように、チェックリストとそのまま使える雛形を提供します。
なぜスクリプト構造が重要か(保守性・テスト・再利用)
短時間で動くスクリプトを書けても、継続的に運用するには設計が必要です。理由は主に以下のとおりです。
- 保守性:誰か(自分含む)が手直ししやすい構造にする
- テスト性:単体関数に分ければ自動テストが書きやすい
- 再利用性:共通処理をモジュール化して別プロジェクトで再利用できる
| 問題 | 影響 | 改善策 |
|---|---|---|
| ワンファイルで処理が直列化 | 変更時に影響範囲が分かりにくい | 関数分割・モジュール化・明確な入出力 |
| 環境依存の設定が直書き | 他環境で動かない、テスト困難 | 環境変数・設定ファイルで分離 |
最低限のプロジェクトレイアウト
簡潔で運用しやすい推奨レイアウトを示します。必要に応じて拡張してください。
| パス | 目的 |
|---|---|
| scripts/ | 実行用スクリプト(cronやsystemdで使う) |
| src/your_package/ | 再利用するモジュール・ビジネスロジック |
| tests/ | ユニットテスト |
| requirements.txt / pyproject.toml | 依存管理 |
| config/ or .env | 環境ごとの設定 |
関数設計の実務(単一責任・入出力を明確に)
関数は「何を受け取り、何を返すか」を明確にします。サイドエフェクト(ファイル書き込み、外部API呼び出し)は最小化し、必要なら別関数に分離します。
| 設計観点 | チェック項目 |
|---|---|
| 単一責任 | 1関数=1目的。入出力が増える場合は分割を検討 |
| 純粋関数優先 | 副作用を分離(例:データ処理と保存を別関数に) |
| 明確な例外処理 | 例外の種類を限定し上位でハンドルする |
モジュールとパッケージ化(__main__ の使い方・importの設計)
エントリポイントは scripts/ に置くか、パッケージの __main__.py を使います。ライブラリ部分は src/ 以下に切り出してテストと再利用を容易にします。
| パターン | 目的・使い方 |
|---|---|
| if __name__ == “__main__” | スクリプト実行時にのみ起動する初期化やCLI接続をここに置く |
| src/your_package/api.py | 外部呼び出しラッパーやビジネスロジックを配置 |
CLI化:argparseでの引数設計とヘルプ
ユーザが使いやすいCLIは引数設計が肝心です。必須・任意・デフォルトを明確にし、helpを丁寧に書きます。
| 引数 | 用途 | 例 |
|---|---|---|
| –config | 設定ファイルのパス | –config config/prod.json |
| –dry-run | 動作確認用(変更は加えない) | –dry-run |
| –log-level | ログ出力レベル | –log-level INFO |
ユーザ向けヘルプのコツ
- 短く何をするかを書き、例を1つ載せる
- 重要な引数は必須にして、デフォルトは説明する
標準ライブラリの実務的な使い方
標準ライブラリをきちんと使うと依存を減らし、長期運用が楽になります。以下に実務でよく使うモジュールと用途をまとめます。
| モジュール | 実務的な使い方 |
|---|---|
| pathlib | OSに依存しないパス操作。ファイルの存在チェックや作成に便利 |
| logging | 運用ログ。ハンドラ分離(コンソールとファイル)、ログ回転はlogging.handlersを使用 |
| os / dotenv / environ | 機密情報や環境差分は環境変数で管理。小規模なら .env を使う |
| json / csv | シリアライズ、データ交換。utf-8での入出力に注意 |
| datetime | UTCベースで管理、フォーマットはISO 8601推奨 |
AI(LLM)連携の実例設計と運用パターン
AI API呼び出しは外部依存のため、堅牢なラッパーを作り、リトライ・検証・ログ記録を行います。ここでは設計パターンと簡単な雛形を示します。
| 設計要素 | 実務ポイント |
|---|---|
| ラッパー関数 | APIキーやエンドポイントは引数化/環境変数化。レスポンスの基本チェック(ステータス、スキーマ)を行う |
| リトライとバックオフ | 短時間の再試行は内製、指数バックオフを実装。10回など過剰なリトライは避ける |
| レスポンス検証 | 必要項目が揃っているか確認し、不正ならエラーを返す |
ラッパーの雛形(概念)
以下はコードの雛形をそのまま貼れる形で示します(簡潔化しています)。必要に応じて HTTP クライアントや認証方法を置き換えてください。
| simple_ai_wrapper.py |
|---|
def call_ai_api(payload, endpoint, api_key, retries=3, backoff=2):
"""シンプルなリトライとレスポンス検証の例
- payload: dict
- endpoint: str
- api_key: str
"""
import time, requests
for attempt in range(1, retries + 1):
resp = requests.post(endpoint, json=payload, headers={"Authorization": f"Bearer {api_key}"}, timeout=30)
if resp.status_code == 200:
data = resp.json()
# 必要な項目チェック例
if "choices" in data:
return data
raise ValueError("Unexpected response structure")
if attempt == retries:
resp.raise_for_status()
time.sleep(backoff ** attempt)
|
運用に向けた実践チェックリスト
デプロイ前にチェックしておきたい項目を一覧にします。SOP(標準作業手順書)への落とし込みをおすすめします。
| カテゴリ | 項目 |
|---|---|
| 環境 | 仮想環境(venv/poetry)と requirements.txt/pyproject の整備 |
| 起動方法 | cron/systemd 用の起動スクリプトとログの標準化 |
| 監視 | ログ出力(レベル別)、エラー通知(メール/Slack)設定 |
| リカバリ | 失敗時の再試行ルールと手動復旧手順の記載 |
| ドキュメント | 使用方法とSOPを README と別に用意 |
付録:コピーして使えるスクリプト雛形
この雛形は、argparse + logging + config読み込み + LLM呼び出しラッパーの最小セットです。適宜置き換えて使ってください。
| template_script.py |
|---|
import argparse
import logging
import json
from pathlib import Path
import os
# 設定読み込み(JSONの例)
def load_config(path):
p = Path(path)
with p.open("r", encoding="utf-8") as f:
return json.load(f)
# シンプルなログ設定
def setup_logging(level):
logging.basicConfig(level=level, format="%(asctime)s %(levelname)s %(message)s")
# AIラッパー(外部ファイルに分けることを推奨)
def call_ai_api(payload, endpoint, api_key, retries=3):
import time, requests
for i in range(1, retries+1):
resp = requests.post(endpoint, json=payload, headers={"Authorization": f"Bearer {api_key}"}, timeout=30)
if resp.status_code == 200:
return resp.json()
if i == retries:
resp.raise_for_status()
time.sleep(2 ** i)
# 処理の主体(入出力は引数化)
def process(data_path, config):
p = Path(data_path)
# ファイル読み込み・処理をここに記述
return {"status": "ok"}
def main():
parser = argparse.ArgumentParser(description="小さなAI呼び出し自動化スクリプト雛形")
parser.add_argument("data_path", help="処理対象ファイルのパス")
parser.add_argument("--config", default="config/prod.json", help="設定ファイルのパス")
parser.add_argument("--log-level", default="INFO", help="ログレベル")
parser.add_argument("--dry-run", action="store_true", help="変更を加えないで実行")
args = parser.parse_args()
setup_logging(args.log_level)
cfg = load_config(args.config)
logging.info("開始: %s", args.data_path)
result = process(args.data_path, cfg)
logging.info("完了: %s", result)
if __name__ == "__main__":
main()
|
よくある落とし穴と回避策
- 直接AWSキーなどをソースに書かない:環境変数やシークレットマネージャを使う
- ログが冗長で必要な情報が埋もれる:ERROR/WARNは必ず人が見られるようにする
- リトライのしすぎ:外部APIに負荷をかけないよう指数バックオフと上限を設定
他記事との連携と次の一歩
ファイル入出力やCSV処理のベストプラクティスは第113回で、テストやCIは第94回で扱っています。次回は並列実行とジョブキューを取り上げ、運用での安全性と拡張性を検討します。
まとめ
本記事では、実務で使えるPythonスクリプトを設計する際の考え方とテンプレートを示しました。ポイントは関数を小さく保ち、設定と実行を分離し、標準ライブラリを有効活用することです。付録の雛形をコピーして、まずは小さな自動化から運用に乗せてみてください。
成果物:記事を読んだらすぐ動かせるサンプルリポジトリ(小さなAI呼び出し自動化スクリプト)を用意しています。次のステップとして、並列実行とジョブ管理の導入を検討してください。