检查环境变量是否存在的良好实践是什么?

我想在Python中检查我的环境中是否存在一个变量,例如"FOO"。为此,我使用了os标准库。在阅读了库的文档之后,我想出了两种方法来实现我的目标:

方法1:

if "FOO" in os.environ:
pass

方法2:

if os.getenv("FOO") is not None:
pass

我想知道哪种方法是一个好的/首选条件,以及为什么。

221965 次浏览

使用第一种;它直接尝试检查environ中是否有定义。虽然第二种形式工作得同样好,但它在语义上有所欠缺,因为如果值存在,则返回只有使用它进行比较。

你试图看看是否有什么东西存在 environ,为什么你要得到只是为了比较它,然后把它扔掉?

这正是getenv所做的:

获取一个环境变量,如果它不存在,返回None。的 可选的第二个参数可以指定另一个默认值

(这也意味着你的支票可能只是if getenv("FOO"))

你不想得到它,你想检查它是否存在。

无论哪种方式,getenv只是environ.get的包装器,但你不会看到人们检查映射中的成员:

from os import environ
if environ.get('Foo') is not None:

总结一下,用:

if "FOO" in os.environ:
pass

如果你只是想检查是否存在,而如果你真的想对你可能得到的值做一些事情,则使用getenv("FOO")

这两种解决方案都有各自的情况,这取决于您想在环境变量存在的条件下做什么。

案例1

当您希望仅根据环境变量的存在而不考虑其值而采取不同的操作时,第一个解决方案是最佳实践。它简洁地描述了您要测试的内容:是环境变量列表中的'FOO'。

if 'KITTEN_ALLERGY' in os.environ:
buy_puppy()
else:
buy_kitten()

案例2

当你想设置一个默认值时,如果这个值没有在环境变量中定义,第二个解决方案实际上是有用的,尽管不是你写的形式:

server = os.getenv('MY_CAT_STREAMS', 'youtube.com')

或者

server = os.environ.get('MY_CAT_STREAMS', 'youtube.com')

注意,如果你的应用程序有几个选项,你可能想看看ChainMap,它允许基于键合并多个字典。在ChainMap文档中有一个例子:

[...]
combined = ChainMap(command_line_args, os.environ, defaults)

为了安全起见

os.getenv('FOO') or 'bar'

上述答案的一个极端情况是设置了环境变量但为空

对于这个特殊的情况

print(os.getenv('FOO', 'bar'))
# prints new line - though you expected `bar`

if "FOO" in os.environ:
print("FOO is here")
# prints FOO is here - however its not

为了避免这种情况,只需使用or

os.getenv('FOO') or 'bar'

然后你得到

print(os.getenv('FOO') or 'bar')
# bar

什么时候环境变量是空的?

你忘记在.env文件中设置值

# .env
FOO=

或导出为

$ export FOO=

或者忘记在settings.py中设置它

# settings.py
os.environ['FOO'] = ''

更新:如果有疑问,查看这些一行程序

>>> import os; os.environ['FOO'] = ''; print(os.getenv('FOO', 'bar'))


$ FOO= python -c "import os; print(os.getenv('FOO', 'bar'))"

如果您想检查是否有多个env变量没有设置,您可以执行以下操作:

import os


MANDATORY_ENV_VARS = ["FOO", "BAR"]


for var in MANDATORY_ENV_VARS:
if var not in os.environ:
raise EnvironmentError("Failed because {} is not set.".format(var))

我推荐以下解决方案。

它会打印您没有包含的env变量,这让您可以一次性添加它们。如果执行for循环,则必须重新运行程序以查看每个丢失的变量。

from os import environ


REQUIRED_ENV_VARS = {"A", "B", "C", "D"}
diff = REQUIRED_ENV_VARS.difference(environ)
if len(diff) > 0:
raise EnvironmentError(f'Failed because {diff} are not set')

考虑到你正在使用一个名为Foo的环境变量,它可能会根据不同的环境而改变,我建议获取它的值并INFO(或DEBUG)记录它,即使你使用它的值(例如布尔值)只是作为一个切换或决策标准。它可以在出现问题时帮助您,或者只是稍后进行完整性检查。

#python=3.8


import os
import logging


foo = os.getenv("FOO")


if foo:
logging.info(f"Proceeding since environment variable FOO exists {foo=}")
pass
else:
# proper action/logging based on the context
pass


我建议不要在没有适当日志记录的情况下在代码本身中硬编码替代方案。使用foo = os.getenv("FOO", "BAR")可以无声地改变代码的行为。

此外,最好将所有常量保存在配置文件中或作为环境变量,不要在源代码本身中硬编码任何内容。默认值和备选项可以放在配置文件中,而改变环境的常量应该是env vars,这样您就可以在部署过程中轻松更改它们。