我想检查我的环境中是否存在 Python 中的变量,例如 "FOO"
。为此,我使用了 os
标准库。在阅读了图书馆的文档后,我想出了两种方法来实现我的目标:
方法一:
if "FOO" in os.environ:
pass
方法二:
if os.getenv("FOO") is not None:
pass
我想知道哪种方法(如果有的话)是一个好的/首选的条件以及为什么。
foo
是否在环境变量中,而不是寻找 foo
是否会导致 None
值。
使用第一个;它直接尝试检查是否在 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'))"
def getenv(key, default=None):
所以如果是这样的话,应该允许默认 vs 或开头的语法
>>> 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))
我推荐以下解决方案。
它会打印您未包含的环境变量,这样您就可以一次添加它们。如果您使用 for 循环,您将不得不重新运行程序以查看每个丢失的 var。
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')
if diff:
就可以了(也许将 diff
更改为 missing_variables
以获得更具描述性的名称)。同样在 python 3.8 及更高版本中,您可以使用 walrus 运算符对其进行更多压缩:if missing_variables := REQUIRED_ENV_VARS.difference(environ):
。
dict
而不是 list
。
set
类型。 print(type({'a', 'b', 'c'}))
产生 <class '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 var,以便您可以在部署期间轻松更改它们。
不定期副业成功案例分享
foo = os.environ.get("FOO"); if foo is not None: do_something(foo)