【问题标题】:What is a good practice to check if an environmental variable exists or not?检查环境变量是否存在的好习惯是什么?
【发布时间】:2017-04-03 12:43:37
【问题描述】:

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

方法一:

if "FOO" in os.environ:
    pass

方法二:

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

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

【问题讨论】:

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

标签: python python-2.7 python-3.x if-statement environment-variables


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    我推荐以下解决方案。

    它会打印您未包含的环境变量,这样您就可以一次将它们全部添加。如果你使用 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'> 作为输出。
    【解决方案3】:

    我的评论可能与给定的标签无关。然而,我是从我的搜索中被引导到这个页面的。 我在 R 中寻找类似的检查,在@hugovdbeg 帖子的帮助下我想出了以下内容。我希望它对在 R 中寻找类似解决方案的人有所帮助

    'USERNAME' %in% names(Sys.getenv())
    

    【讨论】:

      【解决方案4】:

      如果您想检查是否未设置多个环境变量,您可以执行以下操作:

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

      【讨论】:

        【解决方案5】:

        为了安全起见

        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 开头的 or 语法
        • @Chris McKee 试试这个>>> import os; os.environ['FOO'] = ''; print(os.getenv('FOO', 'bar'))
        • 误导性方法签名?
        • @Chris McKee,另一个例子$ FOO= python -c "import os; print(os.getenv('FOO', 'bar'))"
        【解决方案6】:

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

        【讨论】:

        • 感谢您的解释。我会记住这一点。
        【解决方案7】:

        这两种解决方案都有一个案例,具体取决于您要根据环境变量的存在执行什么操作。

        案例一

        当您想纯粹根据环境变量的存在来采取不同的行动,而不关心它的值时,第一个解决方案是最佳实践。它简洁地描述了您测试的内容:环境变量列表中的“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)
        

        【讨论】:

          猜你喜欢
          • 2018-04-07
          • 2012-04-28
          • 2017-11-23
          • 2011-01-21
          • 2011-11-04
          • 1970-01-01
          • 2013-08-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多