概要(dotenvは「設定と秘密をコードから切り離す」開発の定番)
dotenvは、.envファイルに書いた設定値(APIキーやDB接続文字列など)をPython実行時に環境変数へ読み込むための軽量ライブラリです。コードに秘密を直書きせず、安全に差し替えできるのが最大の利点です。要点は、.envの作り方、load_dotenvの呼び方、os.getenvでの取得、そして「本番はOSやプラットフォームの環境変数で注入、開発はdotenvで読み込む」という運用の線引きです。
しくみと導入(python-dotenvで環境変数を扱う)
インストールと基本構成
python-dotenvをインストールし、プロジェクト直下に .env を置きます。実行時に load_dotenv() を呼ぶと、.envのキーと値が環境変数へ反映され、Python側は os.getenv(“KEY”) で取り出せます。これにより、コードは「名前(KEY)だけ」を参照し、実際の値は環境ごとに差し替え可能になります。
.envの置き場と読み込み順
load_dotenv() を引数なしで呼ぶと、カレントディレクトリから .env を探索して読み込みます。別パスなら load_dotenv(“config/.env”) のように明示します。多段構成では find_dotenv() で上位ディレクトリから探索してパスを得てから読み込むと、CLIやテストでも迷子になりません。
基本の使い方(.env作成→読み込み→取得の最短ルート)
.envファイルの作成と内容
.envには KEY=VALUE の形式で1行ずつ書きます。日本語やスペースを含む場合は引用符を使います。例として、APIキー、DB接続文字列、デバッグフラグなどを記述します。
API_KEY=sk_example_123
DATABASE_URL=postgres://user:pass@host:5432/app
DEBUG=1
TIMEOUT=5
Pythonで読み込み・取得
load_dotenv() を呼び、os.getenv で取り出します。必須値は起動時に検証し、欠けていれば早期に停止させます。
# pip install python-dotenv
from dotenv import load_dotenv
import os
load_dotenv() # .env を読み込む
def require(name: str) -> str:
v = os.getenv(name)
if not v:
raise RuntimeError(f"環境変数が未設定: {name}")
return v
API_KEY = require("API_KEY")
DB_URL = require("DATABASE_URL")
DEBUG = os.getenv("DEBUG", "0").lower() in {"1", "true", "yes"}
TIMEOUT = int(os.getenv("TIMEOUT", "5"))
Python値の一覧取得や直接参照
dotenv_values() を使うと、環境へ注入せずに .env の内容を辞書として読むこともできます。設定の検証や差分表示に便利です。
from dotenv import dotenv_values
cfg = dotenv_values() # {"API_KEY": "...", "DATABASE_URL": "...", ...}
Python重要ポイントの深掘り(優先順位・型変換・環境切替・セキュリティ)
優先順位と上書きの制御
dotenvはデフォルトで「既存の環境変数を尊重」します。つまり、OSやコンテナで注入済みの値があれば、それを保持し、.envで上書きしません。意図的に上書きしたい場合は load_dotenv(override=True) を使います。現場では「本番はプラットフォーム注入が最上位、開発は .env を最上位」にする方針を徹底すると混乱が起きにくくなります。
from dotenv import load_dotenv
load_dotenv(override=True) # 既存の環境変数より .env を優先させる
Python型変換とバリデーション
環境変数は文字列で届くため、intやboolへの変換と範囲チェックが必須です。想定外の値は起動直後に弾いて、曖昧な状態で走らせないのが安全です。例えば、数値は int() でパースし、0以下ならエラーにします。真偽値は {“1″,”true”,”yes”} のような集合で解釈を固定すると再現性が上がります。
環境別ファイルの切り替え
開発・検証・本番で設定を分けるなら、.env.development、.env.test、.env.production とファイルを分割し、起動オプションや環境変数(APP_ENVなど)で切り替えます。load_dotenv(f”.env.{APP_ENV}”) のように明示し、デフォルトの .env はローカル開発用に限定すると運用が透明になります。
from dotenv import load_dotenv
import os
env = os.getenv("APP_ENV", "development")
load_dotenv(f".env.{env}") # 例: .env.production を読み込む
Python変数展開(他の値を参照する)
.env 内で ${KEY} の形式による参照が使えるケースがあります。python-dotenvは基本的な展開に対応しており、たとえば BASE_URL と PATH を組み合わせて API_URL を作れます。ただし循環参照や未定義参照は避け、必要なら実行時に組み立てる方が安全です。
BASE_URL=https://api.example.com
API_VERSION=v1
API_URL=${BASE_URL}/${API_VERSION}
セキュリティ運用(開発はdotenv、本番はプラットフォーム)
. env は「開発用の利便ツール」であり、秘密そのものではありません。本番ではクラウドのシークレット管理(環境変数注入やパラメータストア)を使い、.env を持ち込まない運用が理想です。Git管理では .env を .gitignore に含め、共有には .env.example(ダミー値)を配布して初期設定の道筋を示します。
実務例(Web/API設定、テスト、サブプロセス)
Web/APIクライアントの設定読み込み
APIキーやベースURL、タイムアウトを .env で管理すれば、通信コードは環境変数参照だけで済みます。コードの変更なしで接続先切り替えやキー更新ができ、事故を減らせます。
from dotenv import load_dotenv
import os, requests
load_dotenv()
BASE_URL = os.getenv("BASE_URL", "https://api.example.com")
API_KEY = os.getenv("API_KEY", "")
TIMEOUT = int(os.getenv("TIMEOUT", "5"))
def get_user(uid: str):
r = requests.get(f"{BASE_URL}/users/{uid}", headers={"Authorization": f"Bearer {API_KEY}"}, timeout=TIMEOUT)
r.raise_for_status()
return r.json()
Pythonテスト時の差し替えと .env.testing
ユニットテストでは mock.patch.dict で一時的に環境を差し替えるか、テスト用の .env.testing を読み込みます。外部依存を切り離し、期待値に沿った動作確認が簡単になります。
from dotenv import load_dotenv
import os
load_dotenv(".env.testing")
assert os.getenv("DEBUG") == "1"
Pythonサブプロセスへ限定的に注入
親プロセスの環境を汚さず、子プロセスにだけ設定を渡したい場合は os.environ.copy() で辞書を複製して env 引数で渡します。一時的な上書きや追加が安全にできます。
import os, subprocess
from dotenv import load_dotenv
load_dotenv()
env = os.environ.copy()
env["DEBUG"] = "1"
subprocess.run(["python", "worker.py"], env=env, check=True)
Pythonよくある落とし穴と対策(上書き混乱・値の不正・ファイル漏えい)
上書きの意図が不一致になる
既存の環境変数があるのに .env で上書きされない、または逆に上書きされてしまう混乱は定番です。load_dotenv の override を明示し、チーム内で「どちらが最上位か」をルール化すると解消します。ログに現在値を一度だけ出しておくと、早期に気づけます。
値の不正で起動後に落ちる
文字列のまま使って例外が遅れて出ると原因特定が難しくなります。起動直後に require と型変換で弾き、メッセージに「どのキーが不正か」を含めると発見が速くなります。
.envを誤ってコミットする
.gitignore に .env を必ず含め、CI上ではシークレット注入を使います。すでにコミットしてしまった場合は履歴からの完全削除とキーのローテーションが必要です。サンプル共有は .env.example に限定します。
まとめ
dotenvは、設定と秘密をコードから切り離し、環境ごとに安全に切り替えるためのシンプルで強力な仕組みです。基本は「.envを作る→load_dotenv→os.getenv」で最短に動かし、優先順位(overrideの扱い)、型変換と必須チェック、環境別ファイルの切替、セキュリティ運用の線引きを先に決めておくことが重要です。Web/APIの設定管理やテストの差し替え、サブプロセス注入まで一貫した方針で運用すれば、初心者でも短いコードで「安全・柔軟・再現性の高い」設定管理を実現できます。
