ChatGPT解决这个技术问题 Extra ChatGPT

检查环境变量是否存在的好习惯是什么?

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

方法一:

if "FOO" in os.environ:
    pass

方法二:

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

我想知道哪种方法(如果有的话)是一个好的/首选的条件以及为什么。

它主要基于意见。两者都有相同的目的。我会更喜欢方法1,因为它更干净
我不能说里面有什么。选择一个(掷硬币?),如果它不起作用,稍后重新评估。坦率地说,我认为您输入此问题所花费的时间比您节省的时间要多!
@Ayoub:我想你忘了看到问题“检查 Python 中是否存在环境变量的好习惯是什么?”
基于意见。方法 1 的语法效果更好,因为您询问 foo 是否在环境变量中,而不是寻找 foo 是否会导致 None 值。
但这种方式可能并不明显,除非你是荷兰人......

D
Dimitris Fasarakis Hilliard

使用第一个;它直接尝试检查是否在 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")


谢谢你的解释。我会记住这一点。
相反:如果你不打算使用它,为什么要检查它的存在?也许他只是询问错误检查方面,但后来他的程序使用了它。 (这很常见)。在进行检查的同时捕获价值将是最有凝聚力的。有一种不太可能的情况,即 OP 想要在调用需要它的子程序之前进行检查,但奥卡姆剃刀建议这是不太可能的情况。
我是这样做的:foo = os.environ.get("FOO"); if foo is not None: do_something(foo)
h
hugovdberg

两种解决方案都有一个案例,具体取决于您要以环境变量的存在为条件做什么。

情况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)

L
Levon

为了安全起见使用

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'))"

getenv 的签名是 def getenv(key, default=None): 所以如果是这样的话,应该允许默认 vs 或开头的语法
@Chris McKee 试试这个>>> import os; os.environ['FOO'] = ''; print(os.getenv('FOO', 'bar'))
误导性的方法签名😜
@Chris McKee,另一个例子 $ FOO= python -c "import os; print(os.getenv('FOO', 'bar'))"
v
vhamon

如果要检查是否未设置多个 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))

I
Ivo

我推荐以下解决方案。

它会打印您未包含的环境变量,这样您就可以一次添加它们。如果您使用 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):
巧妙的把戏!请注意 var 类型 dict 而不是 list
@MarkHu 它实际上是一个 set 类型。 print(type({'a', 'b', 'c'})) 产生 <class 'set'> 作为输出。
s
stapmoshun

考虑到您正在使用一个名为 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,以便您可以在部署期间轻松更改它们。