Pythonで環境変数を活用する

February 24, 2021
執筆者
レビュー担当者

environment-variables-python

この記事はMiguel Grinbergが執筆したこちらの記事(英語)を日本語訳したものです。

Pythonアプリケーションを構成する際は、環境変数を使用すると非常に便利です。構成を変更する場合に、ソースコードを編集する必要がなくなります。一般的な構成アイテムのうち、環境変数を使用してアプリケーションに渡すことが多いものとしては、サードパーティのAPIキーやネットワークポート、データベースサーバー、アプリケーションの正常な動作に必要なカスタムオプションなどがあります。

この記事では、Pythonで環境変数を使用するためのテクニックやツールを紹介します。

Pythonから環境変数にアクセスする方法

os.environ辞書を使用する

Pythonでは、os.environ辞書がすべての環境変数を保持しています。アプリケーション内から変数を取得する最も簡単な方法は、標準的な辞書型の構文を使用することです。以下の例は、USERという名前の環境変数にアクセスする方法を示しています。

>>> import os
>>> user = os.environ['USER']
>>> user
'miguel'

この方法を使用し、存在しない環境変数をインポートしようとすると、KeyError例外が発生します。

>>> database_url = os.environ['DATABASE_URL']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/miguel/.pyenv/versions/3.8.6/lib/python3.8/os.py", line 675, in __getitem__
    raise KeyError(key) from None
KeyError: 'DATABASE_URL'

os.environ.get()を使用する

プログラムに必須の環境変数については、KeyErrorを受け取ればよいのですが、一部の変数をオプションにしたい場合もあります。エラーを回避するには、辞書型のget()メソッドを使用します。このメソッドは、リクエストされたキーが辞書に存在しない場合、Noneを返します。

>>> database_url = os.environ.get('DATABASE_URL')

変数が定義されていない場合のデフォルト値を追加する

キーが存在しない変数にNone以外のデフォルト値を設定するという場合は、第2引数に値を追加します。

>>> database_url = os.environ.get('DATABASE_URL', 'sqlite:///')
>>> database_url
'sqlite:///'

os.getenv()関数を使用する

Pythonでは、os.getenv()関数を使用して環境変数にアクセスすることもできます。この関数の動作は、os.environ.get()メソッドの動作とよく似ています。以下の例では、この関数を使用して変数にアクセスしています。

>>> user = os.getenv('USER')
>>> user
'miguel'

この関数は、存在しない変数に対しエラーを発生させません。os.environ.get()と同様、Noneを返します。カスタムのデフォルト値を設定した第2引数も受け付けます。

>>> database_url = os.getenv('DATABASE_URL', 'sqlite://')
>>> database_url
'sqlite://'

os.environよりもos.getenv()を使用する方が得策かどうかは開発者次第です。私は個人的に、os.environ辞書を使用する方が好きです。その理由は必須の変数がない場合には、KeyErrorによりプログラムを停止させるという選択肢があるからです。

環境変数の設定方法

このセクションでは、ターミナルやコマンドプロンプトウィンドウで環境変数を設定する方法を簡単に説明します。環境変数のさまざまな設定方法については、同僚のDominik Kundelが、「環境変数の設定方法」というブログ記事で詳細に解説しています。ぜひそちらをご覧ください。

UnixとmacOS

bashやzshのターミナルセッションから環境変数を設定する基本的な方法は、2種類あります。1つは、exportキーワードを使うことです。

export DEBUG=true

この方法で設定された変数は、特定のターミナルセッションから開始した全てのプログラムやスクリプトに渡されます。環境変数はシェルセッションのコンテキスト外には保存されません。ターミナルセッションの終了と同時に消失しますので注意してください。

2つ目の方法は、ターゲットアプリケーションを実行する行の中に環境変数を設定することです。

DEBUG=true python my_cool_application.py

2つ目の方法には、対象アプリケーションの環境スペースにのみ変数を設定できるというメリットがあります。

Microsoft Windows

Windowsを使用している場合、いくつかの選択肢があります。コントロールパネルから環境変数を設定する場合は、前述のブログ記事を参照してください。

コマンドプロンプトウィンドウを使用する場合は、setコマンドを用いて設定できます。

set DEBUG=true

Unixの場合と同様、現行のセッション以外に変数が保存されたり記憶されたりすることはありません。

新しいPowerShellコンソールでは、完全に異なる構文を使用して環境変数を設定します。

$Env:DEBUG = "true"

WSLCygwinなどのUnix互換レイヤーを使用している場合は、Unixセクションを参照し、bashやzsh向けの方法を使用してください。

.envファイルを使用する

環境変数の設定方法がたくさんありすぎて混乱していますか?個人的には、プラットフォームやシェルごとに手順が異なるのは不便だと感じています。

私のお勧めは、.env(読み方「ドットエンブ」)ファイルに環境変数を保存して管理する方法です。.envファイルは、変数を1行に1つ定義したテキストファイルです。.envファイルの形式は、すべてのオペレーティングシステムで全く同じです。そのため、.envファイルを使用すると、どのプラットフォームでも同じ方法で環境変数を使用できます。これではまだ不十分という場合は、Pythonに自動的にインポートされるファイルに環境変数を記述してください。新しいシェルを起動するたびに手動で環境変数を設定する必要がなくなります。

これは、2つの変数を記述した簡単な.envファイルの例です。

DEBUG=true
DATABASE_URL=sqlite:///mydb.sqlite

各プロジェクトのルートディレクトリに.envファイルを作成すると、プロジェクトごとに必要な環境変数を整理して保管できます。

python-dotenvパッケージを使用すると、Pythonアプリケーションが.envファイルで定義された環境変数を環境にインポートします。pipを使用し、仮想環境にpython-dotenvをインストールできます。

pip install python-dotenv

以下は、Pythonアプリケーションに.envファイルをインポートする方法です。

>>> from dotenv import load_dotenv
>>> load_dotenv()

load_dotenv()関数が、現在のディレクトリから.envという名前のファイルを探し、ファイル内の変数定義をすべてos.environ辞書に追加します。現在のディレクトリに.envファイルが見つからない場合は、親ディレクトリを検索します。検索は、.envファイルが見つかるまで、または最上位ディレクトリに到達するまで、ディレクトリ階層をたどりながら進みます。

python-dotenvがディレクトリをたどりながら.envファイルを検索する動作を防ぐには、load_dotenv()にファイルの明示的なパスを引数として渡します。

>>> from dotenv import load_dotenv
>>> load_dotenv('/home/miguel/my_project/.env')

その他にも、load_dotenv()関数を呼び出すときに使用できる引数があります。そうした引数については、こちらのドキュメントを参照してください。

.envファイルがインポートされると、環境変数へのアクセスは、上記のいずれかの方法で行えます。

.envファイルのセキュリティに関する注意事項

.envファイルに、パスワードやAPIキーなどの機密情報を含んだ環境変数を追加することはよくあります。そのため、プロジェクトのソースコントロールリポジトリには、こうしたファイルを追加しないようにするのが一般的です。

標準的な方法は、この名前のファイルに例外を追加し、このファイルを意図せずソースコントロールにコミットしないようにすることです。gitの場合は、リポジトリのルートにある.gitignoreファイルに、このファイル名を記述した1行を追加します。

しかし、.envファイルをコミットできない場合、プロジェクトユーザーにどの変数を設定する必要があるかを伝えるにはどうすればよいでしょうか?この場合、.env.exampleなどの名前を付けた、サンプルとなる.envファイルをリポジトリに追加します。このファイルには、プロジェクトに必要な変数のリストを格納します。値を入れる必要はありません。これにより機密情報を開示することなく、このファイルがプロジェクトユーザーのガイドとして機能します。

まとめ

環境変数を使用してPythonプロジェクトを構成する方法をご理解いただけたでしょうか。

環境変数の使い方についてほかにもアイデアをお持ちの方は、ぜひお聞かせください。

Miguel Grinbergは、Twilioのテクニカルコンテンツ担当Python開発者です。このブログでは皆様のPythonプロジェクトを紹介します。ぜひ、mgrinberg [at] twilio [dot] comまでご連絡ください。