閉じる

Pythonで設定ファイル(JSON/YAML/INI)を読み書きする方法まとめ

アプリの挙動や接続先、フラグなどをコードから切り離して管理するには設定ファイルが便利です。

本記事では、Python初心者の方でも迷わないように、3つの代表的な形式(JSON/YAML/INI)を、インストールから読み書きのサンプル、注意点まで丁寧に解説します。

UTF-8の扱いと例外対策にも触れます。

設定ファイルの基本と事前準備

設定ファイルは、コードを書き換えずに動作を切り替えるための外部ファイルです。

PythonではJSONとINIが標準ライブラリで扱え、YAMLは外部ライブラリ(PyYAML)で扱います。

用途に応じて形式を選ぶことで、読みやすさと安全性、移植性のバランスが取れます。

まずは形式の特徴と準備から確認しましょう。

3形式の使い分け(JSON/YAML/INI)

以下は、よく使われる3形式の比較です。

チーム構成や配布先(他言語やツール)を念頭に置いて選ぶと良いです。

形式特徴向いている用途Pythonでの扱い
JSON軽量、相互運用性が高い、厳密な型(配列/オブジェクト/数値/真偽/文字列/null)Web API・他言語とのデータ交換、設定の標準化標準ライブラリのjson
YAML人が読み書きしやすい、コメント可、アンカーなど表現力が高い手作業で編集する設定、複雑な設定PyYAML(外部)
INIセクション+キー=値のシンプル構造、コメント可小規模な設定、伝統的なアプリ設定標準ライブラリのconfigparser

相互運用性重視ならJSON、手でよく編集するならYAML、最小限で済むならINIという基準が分かりやすいです。

必要なライブラリとインストール(pip/PyYAML)

  • JSON: 標準ライブラリjsonでOK
  • INI: 標準ライブラリconfigparserでOK
  • YAML: PyYAMLのインストールが必要です
Shell
# PyYAMLのインストール
python -m pip install PyYAML

# バージョン確認(必要なら)
python -c "import yaml; print(yaml.__version__)"

プロジェクト単位で環境を分ける場合は仮想環境(venv)を使いますが、その詳細は別記事の範囲とします。

サンプルのフォルダ構成と文字コード(UTF-8)

以降のサンプルで用いるフォルダ構成を示します。

ファイルはUTF-8で保存してください。

project/
  ├─ config/
  │   ├─ config.json
  │   ├─ config.yaml
  │   └─ config.ini
  ├─ json_examples.py
  ├─ yaml_examples.py
  └─ ini_examples.py
  • UTF-8で統一し、open時はencoding="utf-8"を明示すると、文字化けや環境差異を減らせます。

サンプルの設定ファイル内容は次の通りです。

JSON
// config/config.json
{
  "app_name": "SampleApp",
  "debug": true,
  "retry": { "count": 3, "interval": 1.5 },
  "hosts": ["example.com", "api.example.com"],
  "message": "こんにちは"
}
YAML
# config/config.yaml
app_name: SampleApp
debug: true
retry:
  count: 3
  interval: 1.5
hosts:
  - example.com
  - api.example.com
message: "こんにちは"
enabled: on        # ← YAMLでは on は True と解釈されます(注意)
release_date: 2025-09-01  # ← 日付形式も date 型に推測される場合があります
INI
; config/config.ini
[DEFAULT]
app_name = SampleApp
debug = true
retry_count = 3
retry_interval = 1.5

[server]
host = example.com
port = 8080
use_tls = yes
endpoint = https://%(host)s:%(port)s  ; 既定の補間で%(host)sなどを参照可能

PythonでJSONを読み書きする

標準ライブラリjsonを使います。

ファイルからはjson.load、文字列からはjson.loadsを使い分けます。

書き込みはjson.dumpjson.dumpsです。

読み込み(json.load/json.loads)

Python
# json_examples.py
from pathlib import Path
import json

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

def read_json_file():
    # ファイルから読み込む場合は json.load を使用
    with CONFIG_PATH.open(encoding="utf-8") as f:
        data = json.load(f)
    # データは通常 dict として得られます
    print("app_name:", data["app_name"])
    print("retry.count:", data["retry"]["count"])
    print("hosts:", data["hosts"])

def read_json_string():
    # 文字列からパースする場合は json.loads を使用
    json_text = CONFIG_PATH.read_text(encoding="utf-8")
    data = json.loads(json_text)
    print("message:", data["message"])

if __name__ == "__main__":
    read_json_file()
    read_json_string()
実行結果
app_name: SampleApp
retry.count: 3
hosts: ['example.com', 'api.example.com']
message: こんにちは

書き込み(json.dump/json.dumps)

Python
# json_examples.py (続き)
def write_json_file():
    src = json.loads(CONFIG_PATH.read_text(encoding="utf-8"))
    # 値を変更・追加
    src["debug"] = False
    src["last_updated"] = "2025-09-20"

    out_path = BASE_DIR / "config" / "out_config.json"
    # ensure_ascii=False で日本語など非ASCII文字をそのまま書き出し
    with out_path.open("w", encoding="utf-8") as f:
        json.dump(src, f, ensure_ascii=False, indent=2, sort_keys=True)

    # 文字列に整形して出力したいときは dumps
    pretty = json.dumps(src, ensure_ascii=False, indent=2)
    print(pretty)

if __name__ == "__main__":
    write_json_file()
実行結果
{
  "app_name": "SampleApp",
  "debug": false,
  "hosts": [
    "example.com",
    "api.example.com"
  ],
  "last_updated": "2025-09-20",
  "message": "こんにちは",
  "retry": {
    "count": 3,
    "interval": 1.5
  }
}

よく使うオプション(indent/ensure_ascii)

  • indentで整形(人が読みやすい)。開発中や手編集を想定する設定ファイルに有効です。
  • ensure_ascii=Falseで日本語をエスケープせず書き出し。既定(True)だと\u3053\u3093...のように変換されます。
  • ほかにもsort_keys=Trueでキー順を固定でき、差分が安定します。

本番環境でサイズを抑えたい場合は整形なし(indentなし)も検討します。

エラー対策(ファイルパス/例外)

ファイルパスの扱いと例外処理は最初に整備すると安心です。

Pathlibでパスを組み立て、例外ではFileNotFoundErrorjson.JSONDecodeErrorを捕捉します。

Python
from pathlib import Path
import json
from json import JSONDecodeError

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

DEFAULTS = {
    "app_name": "SampleApp",
    "debug": False,
    "retry": {"count": 3, "interval": 1.0},
    "hosts": ["localhost"],
}

def load_config_safe(path: Path):
    try:
        with path.open(encoding="utf-8") as f:
            return json.load(f)
    except FileNotFoundError:
        print("[WARN] 設定ファイルが見つかりません。既定値を使用します:", path)
        return DEFAULTS
    except JSONDecodeError as e:
        print(f"[ERROR] JSONの形式が不正です(行{e.lineno} 列{e.colno}): {e.msg}")
        print("[INFO] 既定値を使用します")
        return DEFAULTS.copy()

if __name__ == "__main__":
    cfg = load_config_safe(CONFIG_PATH)
    print("debug:", cfg["debug"])
実行結果
debug: True

PythonでYAMLを読み書きする

YAMLは人間が読み書きしやすい記法が強みです。

Pythonではyaml.safe_loadyaml.safe_dumpの利用が基本です。

インストール(PyYAML)

Shell
python -m pip install PyYAML

安全性のためyaml.loadではなくyaml.safe_loadを使用します。

読み込み(yaml.safe_load)

Python
# yaml_examples.py
from pathlib import Path
import yaml
import datetime as dt

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

def read_yaml():
    with YAML_PATH.open(encoding="utf-8") as f:
        data = yaml.safe_load(f)  # dictとして読み込まれる
    print("app_name:", data["app_name"])
    print("hosts:", data["hosts"])

    # YAMLは値を型推測します
    print("enabled:", data["enabled"], type(data["enabled"]))  # True と解釈される
    print("release_date:", data["release_date"], type(data["release_date"]))  # date型の可能性

if __name__ == "__main__":
    read_yaml()
実行結果
app_name: SampleApp
hosts: ['example.com', 'api.example.com']
enabled: True <class 'bool'>
release_date: 2025-09-01 <class 'datetime.date'>

書き込み(yaml.safe_dump)

Python
# yaml_examples.py (続き)
def write_yaml():
    with YAML_PATH.open(encoding="utf-8") as f:
        data = yaml.safe_load(f)

    data["debug"] = False
    data["notes"] = "日本語のコメントもOK"

    out_path = BASE_DIR / "config" / "out_config.yaml"
    # allow_unicode=True で日本語をそのまま書き出し
    with out_path.open("w", encoding="utf-8") as f:
        yaml.safe_dump(
            data,
            f,
            allow_unicode=True,      # 日本語をエスケープしない
            sort_keys=False,         # キー順維持(見やすさ重視)
            default_flow_style=False # ブロックスタイルで出力
        )

    # 文字列に出力
    s = yaml.safe_dump(data, allow_unicode=True, sort_keys=False)
    print(s)

if __name__ == "__main__":
    write_yaml()
実行結果
app_name: SampleApp
debug: false
hosts:
- example.com
- api.example.com
message: "こんにちは"
notes: 日本語のコメントもOK
retry:
  count: 3
  interval: 1.5

注意点(インデント/型の推測)

  • インデントはスペースのみで、一般に2スペースまたは4スペース。タブは不可です。
  • YAMLは型を推測します。例えばon/off/yes/noは真偽値に、日付っぽい書式はdateに解釈される場合があります。
    • 文字列として保持したい場合はクォートで囲む(例: "on", "2025-09-01")。
  • フォーマットやコメントを厳密に保持したいニーズが強い場合、ruamel.yamlの採用も検討します(本記事ではPyYAMLに絞ります)。

セキュリティの観点からyaml.loadの無指定使用は避け、必ずsafe_loadを使いましょう

PythonでINIを読み書きする

INIはセクションとキー=値からなるシンプルな形式です。

標準ライブラリconfigparserを使います。

読み込み(configparser.ConfigParser)

Python
# ini_examples.py
from pathlib import Path
from configparser import ConfigParser

BASE_DIR = Path(__file__).resolve().parent
INI_PATH = BASE_DIR / "config" / "config.ini"

def read_ini():
    config = ConfigParser()  # 既定の補間(BasicInterpolation)が有効
    config.read(INI_PATH, encoding="utf-8")

    print("sections:", config.sections())      # ['server'] など
    print("app_name:", config.get("DEFAULT", "app_name"))
    print("endpoint:", config.get("server", "endpoint"))  # %(host)s 等が展開される

if __name__ == "__main__":
    read_ini()
実行結果
sections: ['server']
app_name: SampleApp
endpoint: https://example.com:8080

値の取得(get/getint/getboolean)

Python
# ini_examples.py (続き)
def get_typed_values():
    config = ConfigParser()
    config.read(INI_PATH, encoding="utf-8")

    # 文字列/数値/真偽を型付きで取得
    app = config.get("DEFAULT", "app_name")          # str
    debug = config.getboolean("DEFAULT", "debug")    # bool(yes/true/on を True と解釈)
    retry_count = config.getint("DEFAULT", "retry_count")       # int
    retry_interval = config.getfloat("DEFAULT", "retry_interval")  # float
    use_tls = config.getboolean("server", "use_tls", fallback=False)

    print(app, debug, retry_count, retry_interval, use_tls)

if __name__ == "__main__":
    get_typed_values()
実行結果
SampleApp True 3 1.5 True

書き込み(write)

Python
# ini_examples.py (続き)
def write_ini():
    config = ConfigParser()
    config.read(INI_PATH, encoding="utf-8")

    # 値を更新
    config.set("DEFAULT", "debug", "false")

    # 新しいセクションを追加
    if not config.has_section("paths"):
        config.add_section("paths")
    config.set("paths", "log_dir", "/var/log/sampleapp")
    config.set("paths", "data_dir", "/opt/sampleapp/data")

    out_path = BASE_DIR / "config" / "out_config.ini"
    with out_path.open("w", encoding="utf-8") as f:
        config.write(f)

    print("書き出しました:", out_path)

if __name__ == "__main__":
    write_ini()
実行結果
書き出しました: /path/to/project/config/out_config.ini

生成されたout_config.iniの内容(一部)は次のようになります。

INI
[DEFAULT]
app_name = SampleApp
debug = false
retry_count = 3
retry_interval = 1.5

[server]
host = example.com
port = 8080
use_tls = yes
endpoint = https://%(host)s:%(port)s

[paths]
log_dir = /var/log/sampleapp
data_dir = /opt/sampleapp/data

セクションとキーの書き方

  • セクションは[section]、キーはkey = valueまたはkey: valueで記述します。コメントは;または#
  • オプション名(キー)は既定で小文字化されます。大文字小文字を保持したい場合は次のように設定します。
    • config = ConfigParser()の後にconfig.optionxform = strを設定。
  • 文字列としての%(name)sは補間されます。補間を無効化したい場合はConfigParser(interpolation=None)を使用します。
  • 真偽値はyes/no/true/false/on/off(大文字小文字無視)が認識されます。

INIは型情報を持たないため、読み取り時にgetintgetbooleanで明示的に型変換するのが実用的です。

まとめ

本記事では、Pythonでの設定ファイル(JSON/YAML/INI)の読み書きを、準備から安全な実装、オプションや注意点まで解説しました。

相互運用性重視ならJSON、手編集の多い設定はYAML、最小構成やレガシー互換にはINIが目安です。

どの形式でもUTF-8で統一し、pathlibでパスを扱い、例外処理を入れることで、環境差異や運用時のトラブルを抑えられます。

JSONではensure_ascii=Falseindent、YAMLではsafe_load/safe_dumpと型推測への配慮、INIではgetint/getboolean等の型付き取得を意識すると良いでしょう。

実プロジェクトでは、これらの基本を共通ユーティリティ関数にまとめて再利用性を高めるのも効果的です。

この記事を書いた人
エーテリア編集部
エーテリア編集部

人気のPythonを初めて学ぶ方向けに、文法の基本から小さな自動化まで、実際に手を動かして理解できる記事を書いています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!