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

方法1:

if "FOO" in os.environ:
    pass

方法2:

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

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


使用第一种;它直接尝试检查是否在environ中定义了一些东西。尽管第二种形式也同样有效,但它在语义上有所欠缺,因为如果值存在,则返回值,并且仅将其用于比较。

你想知道周围是否存在某种物质,为什么你只是比较一下,然后把它扔掉呢?

这正是getenv所做的:

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

(这也意味着你的检查可能只是如果getenv("FOO"))

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

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

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)

正如@Levon指出的,如果变量设置为空,可能会返回意外的结果。因此,还应该检查返回值。例如:

combined = ChainMap(command_line_args, os.environ)
server = combined.get("MY_CAT_STREAMS") or defaults["MY_CAT_STREAMS"]

为了安全起见

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

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

对于这个特殊的情况

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

or

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

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

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,这样您就可以在部署过程中轻松更改它们。