投稿日:2020年11月5日
os.environは環境変数を取得できるPythonのビルトインのオブジェクトです。このオブジェクトは非常に便利なのですが、動作が少しだけ複雑です。この記事では実際のコードを交えつつ、このos.environについて詳しく解説しています。
os.environはOSの環境変数を表すマップ型オブジェクトです。
環境変数の読み込みを簡単に行えます。
import os
env = os.environ
print(env["SHELL"])
/bin/bash
os.environからの値の取得はブレース([ ])でのキー指定とget()メソッドを使う方法とで2種類あるのですが、
この2つは指定したキーの値が存在しなかった場合の動作に違いがあるためキチンと使い分けましょう。
値が存在する場合の動作については、どちらも違いはありません。
import os
print(os.environ["SHELL"])
print(os.environ.get("SHELL"))
/bin/bash
/bin/bash
ブレース([ ])で存在しないキーを指定した場合
import os
print(os.environ["AAAAAA"])
KeyError Traceback (most recent call last)
<ipython-input-12-4037482a6e5f> in <module>
----> 1 print(env["AAAAAA"])
/usr/lib/python3.8/os.py in __getitem__(self, key)
673 except KeyError:
674 # raise KeyError with the original key value
--> 675 raise KeyError(key) from None
676 return self.decodevalue(value)
677
KeyError: 'AAAAAA'
エラーが投げられます。
get()メソッドは第2引数にキーが存在しなかった場合のデフォルト値を指定できます。
import os
print(os.environ.get("AAAAA","No Value"))
No Value
使い分けとしては
のように考えると良いでしょう。
os.environはdict型の様に扱えるため、キーを指定し値を変更することができます。
import os
env = os.environ
print("before : {}".format(env["SHELL"]))
env["SHELL"] = "/bin/sh"
print("after : {}".format(env["SHELL"]))
before : /bin/bash
after : /bin/sh
setdefault()関数を使うと、値が存在しない場合のみ値を入れることもできます。
import os
# 値が存在しない場合にはセット
print("before : {}".format(os.environ.get("AAAAA","NO_VALUE")))
os.environ.setdefault("AAAAA","/bin/sh")
print("after : {}".format(os.environ.get("AAAAA","NO_VALUE")))
# 値がある場合にはスルー
print("before : {}".format(os.environ.get("SHELL","NO_VALUE")))
os.environ.setdefault("SHELL","/bin/sh")
print("after : {}".format(os.environ.get("SHELL","NO_VALUE")))
『環境変数をマッピングしたコレクションの値を変えて何の意味があるの?』
と思う方もいるかもしれません。
実はos.environの値を変更した場合、環境変数自体が更新されるのです。
値の変更・削除などをして確認してみましょう。
import os
env = os.environ
os.system("echo SHELL=$SHELL")
env["SHELL"] = "/bin/sh"
os.system("echo SHELL=$SHELL")
env.pop("SHELL")
os.system("echo SHELL=$SHELL")
SHELL=/bin/bash
SHELL=/bin/sh
SHELL=
このようにos.environの値をかえると環境変数自体が変更されていることがわかります。
os.environはos._Environというクラスであり、dict型とは少し違います。
import os
print(type(os.environ))
<class 'os._Environ'>
os._Environクラスはcollections.abc.MutableMappingを継承したMapping型になっています。
print(type(os.environ).mro())
[<class 'os._Environ'>,
<class 'collections.abc.MutableMapping'>,
<class 'collections.abc.Mapping'>,
<class 'collections.abc.Collection'>,
<class 'collections.abc.Sized'>,
<class 'collections.abc.Iterable'>,
<class 'collections.abc.Container'>,
<class 'object'>]
この_Environクラスなのですが、__setitem__()と__delitem__()が次の様にカスタマイズされています。
class _Environ(MutableMapping):
def __init__(self, data, encodekey, decodekey, encodevalue, decodevalue):
[...]
def __setitem__(self, key, value):
key = self.encodekey(key)
value = self.encodevalue(value)
putenv(key, value)
self._data[key] = value
def __delitem__(self, key):
encodedkey = self.encodekey(key)
unsetenv(encodedkey)
try:
del self._data[encodedkey]
except KeyError:
# raise KeyError with the original key value
raise KeyError(key) from None
[...]
putenv()やunsetenv()は指定されたキーの環境変数を書き換える関数です。
2020年10月現在の話ですが、
某有名プログラミングスクールさんのブログにos.environ()などと書いてありますが、
os.environはオブジェクトです。
os.environ()のようにメソッドで呼ぶことはできません!!