アプリの挙動や接続先、フラグなどをコードから切り離して管理するには設定ファイルが便利です。
本記事では、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
のインストールが必要です
# 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"
を明示すると、文字化けや環境差異を減らせます。
サンプルの設定ファイル内容は次の通りです。
// config/config.json
{
"app_name": "SampleApp",
"debug": true,
"retry": { "count": 3, "interval": 1.5 },
"hosts": ["example.com", "api.example.com"],
"message": "こんにちは"
}
# 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 型に推測される場合があります
; 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.dump
とjson.dumps
です。
読み込み(json.load/json.loads)
# 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)
# 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でパスを組み立て、例外ではFileNotFoundError
とjson.JSONDecodeError
を捕捉します。
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_load
とyaml.safe_dump
の利用が基本です。
インストール(PyYAML)
python -m pip install PyYAML
安全性のためyaml.load
ではなくyaml.safe_load
を使用します。
読み込み(yaml.safe_load)
# 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)
# 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)
# 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)
# 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)
# 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
の内容(一部)は次のようになります。
[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は型情報を持たないため、読み取り時にgetint
やgetboolean
で明示的に型変換するのが実用的です。
まとめ
本記事では、Pythonでの設定ファイル(JSON/YAML/INI)の読み書きを、準備から安全な実装、オプションや注意点まで解説しました。
相互運用性重視ならJSON、手編集の多い設定はYAML、最小構成やレガシー互換にはINIが目安です。
どの形式でもUTF-8で統一し、pathlib
でパスを扱い、例外処理を入れることで、環境差異や運用時のトラブルを抑えられます。
JSONではensure_ascii=False
とindent
、YAMLではsafe_load/safe_dump
と型推測への配慮、INIではgetint/getboolean
等の型付き取得を意識すると良いでしょう。
実プロジェクトでは、これらの基本を共通ユーティリティ関数にまとめて再利用性を高めるのも効果的です。