閉じる

PythonでYAMLファイルを効率的に読み書きする方法:PyYAMLとruamel.yamlの使い分けを解説

Pythonプログラミングにおいて、設定ファイルやデータのシリアライズ形式としてYAML(YAML Ain’t Markup Language)は欠かせない存在です。

読みやすさと書きやすさを兼ね備えたYAMLは、機械学習のパラメータ管理からWebアプリケーションのコンフィグレーションまで幅広く利用されています。

しかし、Python標準ライブラリにはYAMLパーサーが含まれていないため、開発者は用途に応じて適切な外部ライブラリを選択する必要があります。

本記事では、デファクトスタンダードであるPyYAMLと、高度な機能を持つruamel.yamlの違いを明確にしながら、効率的な読み書きの実装方法を詳しく解説します。

YAMLの基本構造とPythonでの重要性

YAMLは、JSONと同様に構造化データを表現するためのフォーマットですが、インデントを利用して階層を表現するため、人間にとっての視認性が非常に高いという特徴があります。

特にPythonエンジニアにとって、インデントによってブロックを制御するYAMLの文法は親しみやすく、多くのプロジェクトで採用されています。

PythonでYAMLを扱う主な場面には、以下のようなものがあります。

  1. アプリケーションの設定ファイル(config.yamlなど)
  2. Docker ComposeやKubernetesの定義ファイル操作
  3. 機械学習モデルのハイパーパラメータ保存
  4. ログ出力の構造化

これらの用途において、単に読み書きができるだけでなく、「コメントを保持したい」「データの順序を維持したい」「安全にロードしたい」といった細かなニーズが発生します。

これらを実現するために、まずはライブラリの選定から始めましょう。

ライブラリの選定:PyYAML vs ruamel.yaml

PythonでYAMLを扱うライブラリはいくつか存在しますが、主流は以下の2つです。

PyYAMLの特徴

PyYAMLは、Python界で最も普及しているYAMLライブラリです。

非常に高速で動作し、シンプルなAPIを提供しているため、一般的な用途の多くをカバーできます。

  • 長所:広く使われており、情報が豊富。パフォーマンスが良い。
  • 短所:YAMLのコメントを保持できない。YAML 1.1に準拠(一部1.2対応)している。

ruamel.yamlの特徴

ruamel.yamlは、PyYAMLから派生したライブラリで、より高度な制御が可能です。

  • 長所YAML 1.2を完全にサポートしており、読み込んだYAML内のコメントやフォーマットを維持したまま書き戻す(ラウンドトリップ)ことが可能。
  • 短所:PyYAMLに比べて動作がやや低速で、APIが少し複雑。

用途に応じて、単純な読み書きならPyYAML、設定ファイルをプログラムで編集してコメントも残したいならruamel.yamlを選ぶのが定石です。

PyYAMLによる基本的な読み書き

まずは、最も利用頻度の高いPyYAMLの使い方を確認しましょう。

ライブラリがインストールされていない場合は、以下のコマンドでインストールします。

Shell
pip install pyyaml

YAMLファイルの読み込み

YAMLファイルを読み込む際は、セキュリティの観点から必ず yaml.safe_load() を使用してください。

Python
import yaml

# YAML形式の文字列
yaml_content = """
database:
  host: localhost
  port: 5432
  users:
    - admin
    - developer
"""

# 読み込みの実行
data = yaml.safe_load(yaml_content)

print(f"Host: {data['database']['host']}")
print(f"Users: {data['database']['users']}")
実行結果
Host: localhost
Users: ['admin', 'developer']

注意点: 以前のバージョンでは yaml.load() が使われていましたが、これは任意のPythonオブジェクトを実行できてしまう脆弱性の原因となるため、現在は推奨されていません。

YAMLファイルへの書き出し

Pythonの辞書オブジェクトをYAML形式で保存するには yaml.dump() を使用します。

Python
import yaml

config = {
    'server': {
        'timeout': 30,
        'debug': False
    },
    'tags': ['web', 'production']
}

# ファイルへの書き出し
with open('config.yaml', 'w', encoding='utf-8') as f:
    yaml.dump(config, f, default_flow_style=False, allow_unicode=True)

default_flow_style=False を指定することで、JSONのような横並びの形式(フロースタイル)ではなく、ブロックスタイル(インデント形式)で出力されます。

また、日本語を含む場合は allow_unicode=True が必須です。

ruamel.yamlによる高度な操作

次に、設定ファイルの編集などに最適なruamel.yamlの使い方を解説します。

Shell
pip install ruamel.yaml

コメントを維持したまま更新する(ラウンドトリップ)

ruamel.yamlの最大の特徴は、既存のYAMLファイルのコメント位置やインデントを壊さずに値を書き換えることができる点にあります。

Python
from ruamel.yaml import YAML

yaml_text = """
# サーバの設定
server:
  port: 8080  # ポート番号を変更しないでください
  debug: true
"""

yaml = YAML()
# YAML 1.2を維持する設定
yaml.preserve_quotes = True

# 読み込み
data = yaml.load(yaml_text)

# 値の変更
data['server']['port'] = 9000

# 出力の確認
import sys
yaml.dump(data, sys.stdout)
YAML
# サーバの設定
server:
  port: 9000  # ポート番号を変更しないでください
  debug: true

PyYAMLでは消えてしまうはずの # サーバの設定 というコメントが、しっかりと維持されていることがわかります。

これは自動化ツールや設定編集スクリプトを作成する際に非常に強力な武器となります。

PyYAMLとruamel.yamlの機能比較

各ライブラリの特性を整理して比較表にまとめました。

機能PyYAMLruamel.yaml
YAMLバージョン1.1 (一部1.2)1.2
コメントの保持不可(削除される)可能
読み込み速度高速中速
書き出しの制御基本的高度(インデント幅など)
推奨用途データ通信、単純なログ設定ファイルの編集、CI/CDツール

実践的なテクニック:効率的なYAML操作のために

実務でYAMLを扱う際には、単なる読み書き以外にも考慮すべき点があります。

複数のドキュメントを扱う

ひとつのYAMLファイル内に --- (セパレータ)で区切られた複数のデータ構造が含まれている場合があります。

これを扱うには load_all を使用します。

Python
import yaml

multi_document = """
name: Doc1
---
name: Doc2
"""

documents = yaml.safe_load_all(multi_document)

for doc in documents:
    print(doc['name'])
実行結果
Doc1
Doc2

カスタムクラスのシリアライズ

Pythonの自作クラスをYAMLとして保存したり、逆にYAMLからクラスを復元したりすることも可能です。

ただし、セキュリティリスクを避けるため、信頼できるデータソースに対してのみ行ってください。

Python
import yaml

class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __repr__(self):
        return f"User(name={self.name}, age={self.age})"

# カスタムタグの定義
def user_representer(dumper, data):
    return dumper.represent_mapping('!User', {'name': data.name, 'age': data.age})

yaml.add_representer(User, user_representer)

user = User("Taro", 25)
print(yaml.dump(user))
YAML
!User
age: 25
name: Taro

パフォーマンスと安全性のベストプラクティス

YAMLは非常に柔軟なフォーマットですが、扱い方を誤るとパフォーマンスの低下や脆弱性を招きます。

1. 常にSafeLoaderをデフォルトにする

PyYAMLを使用する際は、外部からの入力を処理する場合、必ず safe_load を使用することをチーム内で徹底してください。

これにより、任意のコード実行を防ぐことができます。

2. 大規模なYAMLファイルの分割

数MBを超えるような巨大なYAMLファイルは、解析に多大なメモリを消費します。

可能であれば、複数の小さなファイルに分割するか、構造をフラットに保つことがパフォーマンス向上の鍵となります。

3. データの型を意識する

YAMLは「0123」を整数として解釈するか、文字列として解釈するかで挙動が変わることがあります。

意図しない型変換を防ぐために、クォート(引用符)を適切に使用するよう、生成プログラム側で制御することが重要です。

まとめ

本記事では、PythonでYAMLファイルを効率的に読み書きする方法として、PyYAMLruamel.yamlの2つのライブラリを中心に解説しました。

  • PyYAML:高速かつシンプルで、一般的なデータの読み書きに最適。
  • ruamel.yaml:コメント保持やYAML 1.2対応が必要な、高度な設定ファイル編集に最適。

開発するアプリケーションの要件に応じてこれらを使い分けることで、メンテナンス性の高いコードを実現できます。

特に、人間が直接編集する設定ファイルをプログラムで操作する場合は、ruamel.yamlによるラウンドトリップ処理が非常に有効です。

YAMLは一見シンプルですが、奥が深いフォーマットです。

この記事を参考に、安全で効率的なデータ処理をPythonで実装してみてください。

URLをコピーしました!