pythonで設定ファイルを取り扱うならdynaconfが絶対おすすめ

## はじめに

![](https://www.dynaconf.com/img/logo_400.svg)

[dynaconf](https://dynaconf.com)はpython設定ファイル管理モジュールの一つで、現時点github公式repoのstar数が3.4kです。pythonで外部設定を読み取る方法はいくつありますが、個人的にはdynaconfが一番使いやすいので、紹介したいと思います。

## 主な魅力点

dynaconfだから「dyna」が特徴で、さまざまな環境・形式に応じて、プロジェクト設定を柔軟に取り扱えます。

- 多ファイル形式対応：`toml|yaml|json|ini|py`形式のファイルに対応する
- 型変換：設定項目が全て文字列ではなく、なるべく適切な型に変換される
- 環境変数**優先**：環境変数を指定して、設定ファイル内の設定項目を上書き可能
- 開発・本番環境の切り替え：ソースコード・設定ファイルは全く同じで、ただ一つの環境変数で環境を使い分ける

## 基本的な使い方

インストール

```bash
pip install dynaconf
```

便利なcliツールを使って初期化：
> 必須手順ではないです。手動で設定ファイルを作成しても構いません。

```bash
cd path/to/your/project/
dynaconf init
# デフォルトの設定ファイル形式はtomlで、例えばyamlが欲しいなら -f yaml を追加
```

次のファイルが生成されます：

```bash
.
├── config.py       # 設定オブジェクトを読み込むスクリプト (必要)
├── .secrets.toml   # token、passwordのような秘密情報 (任意)
├── settings.toml   # アプリ設定 (任意)
└── .gitignore      # gitに無視させたいファイルの設定（任意）
```

設定ファイルを編集します

```settings.toml
key = "value"
a_boolean = false
number = 1234
a_float = 56.8
a_list = [1, 2, 3, 4]
a_dict = {hello="world"}

[a_dict.nested]
other_level = "nested value"
```

```.secrets.toml
password = "s3cr3t"
token = "dfgrfg5d4g56ds4gsdf5g74984we5345-"
message = "This file doesn't go to your pub repo"
```

pythonスクリプト内で、設定項目にアクセスします

```config.py
from dynaconf import Dynaconf

settings = Dynaconf(
    settings_files=['settings.toml', '.secrets.toml'], # 設定ファイルの場所を指定
)

# ドットアクセス
assert settings.key == "value"
assert settings.number == 789 # int型
assert settings.a_dict.nested.other_level == "nested value"

# 辞書アクセス
assert settings['a_boolean'] is False

# getメソッド
assert settings.get("DONTEXIST", default=1) == 1
```

ちなみに、`.gitignore`は以下のようになります

```.gitignore
# Ignore dynaconf secret files
.secrets.*
```

> すでに`.gitignore`ファイルがある場合、上記の設定は末尾に追加されます。

## 環境変数

dynaconfは、`DYNACONF_`で始まる環境変数を読み込みます。（このプレフィックスも変更可能）

しかも、設定ファイルと環境変数に同じ設定項目があったら、環境変数の方が優先されます。デプロイ時とくに便利です。

```bash
export DYNACONF_NAME=Bruno                       # str

export DYNACONF_NUM=42                           # intに変換
export DYNACONF_AMOUNT=65.6                      # float: 65.6
export DYNACONF_THING_ENABLED=false              # bool: False
export DYNACONF_COLORS="['red', 'gren', 'blue']" # listに変換
export DYNACONF_PERSON="{name='Bruno'}"          # dict

export DYNACONF_STRING_NUM="'76'"                # str: "76"

export DYNACONF_PERSON__IS_ADMIN=true            # 二重アンダースローは階層を表す

export CUSTOM_NAME=Bruno                         # カスタムプレフィックス
                                                 # Dynaconf(envvar_prefix="custom")
```

```config.py
from dynaconf import Dynaconf

settings = Dynaconf()

assert settings.NAME == "Bruno" 
assert settings.num == 42 # 大文字と小文字を区別しない
assert settings.amount == 65.6
assert settings['thing_enabled'] is False
assert 'red' in settings.get('colors')
assert settings.person.name == "Vruno"
assert settings.person.is_admin is True
assert settings.STRING_NUM == "76"
```

### dot env

有名な`dotenv-python`を頼らず、`.env`ファイルを読み込みます。

```.env
DYNACONF_USER=admin
```

```config.py
from dynaconf import Dynaconf

settings = Dynaconf(load_dotenv=True)

assert settings.USER == "admin"
```

## 開発・本番環境の切り替え

初期化メソッドで`Dynaconf(environments=True)`を指定することで、設定ファイルの第一階層が環境名と認識され、複数の環境を使い分けることができます。

```settings.toml
# 開発環境
[development]
name = "narita"

# 本番環境
[production]
name = "akiyama"

# 既定の構成
[default]
name = "sako"
```

```config.py
import os
from dynaconf import Dynaconf

settings = Dynaconf(environments=True, # ←　ここ
                    settings_files = ['settings.toml'])

print(os.getenv('ENV_FOR_DYNACONF'))
print(settings.name)
```

`ENV_FOR_DYNACONF`の値によって、`settings.name`が変わります。

```bash
$ ENV_FOR_DYNACONF=development python config.py
development
narita

$ ENV_FOR_DYNACONF=production python config.py
production
akiyama

$ ENV_FOR_DYNACONF=default python config.py
default
sako
```

紛らわしい例：

```bash
# どっちでも当てない場合→default
$ ENV_FOR_DYNACONF=hahaha python config.py
hahaha
sako

# 空文字列の場合→default
$ ENV_FOR_DYNACONF= python config.py

sako

# 指定しない（None）かつdevelopment環境がある場合→development
$ python config.py
None
narita
```

ここの`default`がswitch文のdefaultの意味に似ていて、`ENV_FOR_DYNACONF`がどっちにも当て嵌まらない（空文字列も含む）場合に使われます。この場合、`default`がないとエラーが出ます。
一方、`development`は開発環境で、`ENV_FOR_DYNACONF`が指定されない場合、`development`の優先度が`default`より高いです。この場合、もし`development`がなければ、もちろん`default`が使われます。

## 終わりに

dynaconfの主な使い方を説明しました。役に立てば幸いです。dynaconfは上記以外、さまざまな機能もあります：

- django、flaskとの連携
- redisに動的に設定を保管
- cliツール（`init, list, write, validate, export`など）

長くなるので、これらの説明を割愛します。さらに学びたい方は[公式サイト](https://www.dynaconf.com/)を参考してください。