Python | 自動化:設定ファイル(YAML)

Python
スポンサーリンク

概要(設定ファイル=「コードの外に出したルール表」)

設定ファイル(YAML)は、
「スクリプトの中にベタ書きしていた値(パス・日付・URL・モードなど)を、コードの外に出しておくための“ルール表”」
だと考えてください。

例えば、今こう書いているとします。

INPUT_DIR = "data/input"
OUTPUT_DIR = "data/output"
API_BASE_URL = "https://api.example.com/v1"
Python

パスや URL を変えたくなるたびに、ソースコードを書き換えることになります。
これを config.yaml というファイルに出しておいて、Python 側は「その設定を読むだけ」にすると、

コードは変えずに設定だけ変えて挙動を変えられる
テスト用・本番用など環境ごとに設定ファイルを分けられる
他の人にも使いやすく説明しやすい

という状態になります。

ここでは、Python 自動化でよくあるパターンを題材にしながら、YAML の基礎から実戦的な使い方まで順番に解説します。


YAML の超基本(JSON より人間に優しい書き方)

YAML は「人間が読み書きしやすい辞書・リスト」

YAML は、ざっくり言うと「人間が読み書きしやすい JSON」みたいなものです。
中身自体は、Python 側で読み込むと、ほぼそのまま dict(辞書)や list(リスト)になります。

例えば、こんな config.yaml があったとします。

paths:
  input_dir: "data/input"
  output_dir: "data/output"

api:
  base_url: "https://api.example.com/v1"
  timeout: 5.0
  retries: 3

mode: "production"
YAML

インデント(スペース)で階層を表現しています。
paths.input_dir のような「階層付きの設定」を、見やすく整理できるのがポイントです。

JSON との違いイメージ

JSON で書くとこうなります。

{
  "paths": {
    "input_dir": "data/input",
    "output_dir": "data/output"
  },
  "api": {
    "base_url": "https://api.example.com/v1",
    "timeout": 5.0,
    "retries": 3
  },
  "mode": "production"
}

波かっこ・かっこ・カンマだらけで、人間が手で編集するには少ししんどいですよね。
YAML は、インデントと改行中心で書けるので、設定ファイル向きだとよく使われます。


Python から YAML 設定を読む基本(PyYAML)

ライブラリの準備と最小コード

Python で YAML を扱うには、一般的に PyYAML を使います。

pip install pyyaml

最小の読み込みコードはこんな感じです。

# config_loader.py
import yaml
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent
CONFIG_PATH = BASE_DIR / "config.yaml"

def load_config(path: Path = CONFIG_PATH) -> dict:
    with path.open("r", encoding="utf-8") as f:
        data = yaml.safe_load(f)
    return data

if __name__ == "__main__":
    config = load_config()
    print(config)
    print(config["paths"]["input_dir"])
Python

yaml.safe_load で YAML を読み込むと、Python の dict / list に変換されます。
先ほどの config.yaml なら、

config["paths"]["input_dir"]  # "data/input"
config["api"]["timeout"]      # 5.0
config["mode"]                # "production"
Python

のように参照できます。

ここでの重要ポイントは、

コード側は「キーの名前」だけを知っていればよく、値そのものは YAML 側で自由に変えられる
パスや URL、タイムアウト秒数などをハードコードせずに済む

ということです。


自動化スクリプトと設定ファイルを分離する実例

例:データ収集 BOT の設定を YAML に出す

例えば「API からデータを取って CSV に保存する BOT」を考えます。
設定にしたいものは、だいたいこんな感じです。

どの API を叩くか(base_url、エンドポイント)
どのディレクトリに保存するか
タイムアウトやリトライ回数
動作モード(本番/検証)

これを config.yaml にまとめるとします。

paths:
  base_dir: "data"
  logs_dir: "logs"

api:
  base_url: "https://api.example.com/v1"
  timeout: 5.0
  retries: 3

job:
  mode: "production"   # or "staging"
  batch_size: 100
YAML

Python 側では、設定を読み込んでから処理に渡します。

# data_bot.py
import logging
from pathlib import Path

import requests
import yaml

BASE_DIR = Path(__file__).resolve().parent
CONFIG_PATH = BASE_DIR / "config.yaml"

def load_config(path: Path = CONFIG_PATH) -> dict:
    with path.open("r", encoding="utf-8") as f:
        return yaml.safe_load(f)

def setup_logging(logs_dir: Path):
    logs_dir.mkdir(exist_ok=True)
    log_file = logs_dir / "bot.log"
    logging.basicConfig(
        filename=log_file,
        level=logging.INFO,
        format="%(asctime)s [%(levelname)s] %(name)s - %(message)s"
    )

def fetch_items(base_url: str, timeout: float):
    url = f"{base_url}/items"
    resp = requests.get(url, timeout=timeout)
    resp.raise_for_status()
    return resp.json()

def run_bot(config: dict):
    paths_cfg = config["paths"]
    api_cfg = config["api"]
    job_cfg = config["job"]

    data_dir = BASE_DIR / paths_cfg["base_dir"]
    logs_dir = BASE_DIR / paths_cfg["logs_dir"]

    data_dir.mkdir(exist_ok=True)
    setup_logging(logs_dir)

    logging.info(f"BOT開始 mode={job_cfg['mode']}")
    items = fetch_items(api_cfg["base_url"], api_cfg["timeout"])
    logging.info(f"取得件数: {len(items)}")
    # ここに保存処理などを書く

def main():
    config = load_config()
    run_bot(config)

if __name__ == "__main__":
    main()
Python

ここで深掘りしたいのは、「設定ファイルとロジックを分ける」感覚です。

コード側は、「config のどこに何が書いてあるか」(キー構造)だけ知っている
値そのもの(URL、パス、mode)は、完全に YAML 側に追い出した

この状態になると、

テスト環境用 config.staging.yaml
本番環境用 config.production.yaml

のようにファイルを分けて、起動時にどちらを読むか変えるだけで切り替えができます。


設定ファイル設計の重要ポイントを深掘りする

1. 「コードで変えないもの」を設定に、「頻繁に変えないもの」だけ出す

何でもかんでも設定ファイルに出せばいいわけではありません。

設定ファイルに出すべきものは、主にこういうものです。

環境ごとに変わる値(パス、URL、モード、batch_size など)
本番運用中にも変えたい可能性がある値(リトライ回数、タイムアウト、しきい値など)

逆に、ビジネスロジックそのもの(「こう計算する」「こう分岐する」など)を全部 YAML に埋め込もうとすると、
かえって分かりにくく、動作確認もしづらくなります。

目安としては、

「これはコードを書き換えずに変えたいか?」

と自分に問いかけて、Yes なら設定に出す、No ならコードに残す、くらいでちょうど良いです。

2. キー構造を丁寧に決める(paths / api / job などに分ける)

設定ファイルが大きくなってくると、

どこに何が書いてあるか分からない
同じ意味のパスが別名で複数書いてある

というカオス状態になりがちです。

それを防ぐために、トップレベルをざっくり「カテゴリ」で分けます。

例としては、

paths: ファイルパス・ディレクトリ関連
api: Web API 関連(base_url、timeout、retries 等)
job: バッチの動作モードや対象範囲

のようにするイメージです。

Python 側でも、

paths_cfg = config[“paths”]
api_cfg = config[“api”]
job_cfg = config[“job”]

とカテゴリごとに取り出せるので、見通しが良くなります。

3. デフォルト値と設定ファイルの優先順位

全部を YAML に書き切る必要はありません。
「ほぼ固定の値」は Python 側にデフォルトを持たせつつ、YAML で上書きできるようにする、という設計も有効です。

例えば、

DEFAULT_TIMEOUT = 5.0
timeout = config["api"].get("timeout", DEFAULT_TIMEOUT)
Python

のようにしておけば、config.yaml に timeout がなければ 5.0 秒、
あればその値を使う、という柔らかい設計になります。

これを徹底すると、「設定ファイルがちょっと足りなくても動く」ので、
設定ファイル増殖時の移行(新旧フォーマットの混在)にも対応しやすくなります。


YAML の書き方でよく使うパターン(初心者向け)

キーと値、インデントの基本

最も基本は「キー: 値」です。

mode: "production"
batch_size: 100
timeout: 5.0
YAML

文字列はダブルクオートなしでも書けますが、
日本語や特殊文字を含むときは "..." で囲んでおくと安心です。

インデントはスペース(通常2か4)で統一します。タブは使わない方が安全です。

paths:
  input_dir: "data/input"
  output_dir: "data/output"
YAML

paths の下にある 2 行は、同じ階層のキーであることをスペースの位置で表現しています。

リスト(配列)を書きたいとき

例えば、「対象ユーザーIDのリスト」を設定にしたい場合。

targets:
  users:
    - 1001
    - 1002
    - 1003
YAML

Python 側で読み込むと、

config["targets"]["users"]  # [1001, 1002, 1003]
Python

という list になります。

処理対象の一覧や、「この API を使うかどうかのフラグの束」などに、リストはよく使います。

コメントで意味を残す

YAML では # 以降がコメントになります。

job:
  mode: "production"   # "staging" にするとテストモード
  batch_size: 100      # 一度に処理する件数
YAML

コメントは「自分と他人への説明書」です。
設定の意味や、許容値の範囲などを書いておくと、壊しづらくなります。


設定ファイルと秘密情報(APIキーなど)の扱い

YAML に書いてはいけないもの(原則)

設定ファイルに何でも書きたくなりますが、
絶対に気をつけたいのが「秘密情報」です。

具体的には、

APIキー・トークン
パスワード
DB の接続文字列

などです。

これらを YAML に書いてしまうと、

Git に乗って漏れる
他の人に設定ファイルを渡したときに漏れる

など、かなり危険です。

秘密情報は環境変数、その他は YAML に

実務的には、

秘密情報(APIキーなど) → 環境変数(os.environ)
それ以外の設定(URL、パス、モードなど) → YAML

という分業がよく使われます。

例えば、YAML には「どのサービスを使うか」だけ書き、

api:
  base_url: "https://api.example.com/v1"
  timeout: 5.0
YAML

実際のキーは環境変数から読みます。

import os

API_KEY = os.environ.get("MY_API_KEY")
Python

このようにすると、ソースや config.yaml を他人と共有しても、
秘密そのものは環境側にしか存在しない、という状態を保てます。


まとめ(設定ファイル+YAMLは「コードを長生きさせる」ための土台)

Python 自動化と YAML 設定ファイルを結びつけて整理すると、ポイントはこうなります。

設定ファイルは、「環境や運用に応じて変わる値」をコードから切り離すための“ルール表”。
YAML は JSON より人間が読み書きしやすく、階層化された設定(paths / api / job など)を綺麗に表現できる。
PyYAML(yaml.safe_load)で YAML を dict として読み込み、コード側は「キー構造だけ」を前提にロジックを書く。
何でもかんでも設定に出すのではなく、「コードを書き換えずに変えたいもの」だけを YAML に出す。
秘密情報は環境変数、その他の設定は YAML に分けて扱うことで、安全性と運用性を両立する。

このスタイルが身につくと、
今までは「パスを書き換えて保存して…」とやっていたスクリプトが、
config.yaml をちょっと変えるだけで、別環境・別条件でも動かせるようになります。

タイトルとURLをコピーしました