【问题标题】:How to set environment variables in Python?如何在 Python 中设置环境变量?
【发布时间】:2011-08-23 16:48:19
【问题描述】:

我需要在 Python 脚本中设置一些环境变量,并且我希望从 Python 调用的所有其他脚本都能看到环境变量的设置。

如果我这样做,

os.environ["DEBUSSY"] = 1

它抱怨说1 必须是一个字符串。

我也想知道一旦我设置了它,如何在 Python 中读取环境变量(在脚本的后半部分)。

【问题讨论】:

标签: python environment-variables


【解决方案1】:

环境变量必须是字符串,所以使用

os.environ["DEBUSSY"] = "1"

将变量DEBUSSY设置为字符串1

以后要访问这个变量,只需使用:

print(os.environ["DEBUSSY"])

子进程自动继承父进程的环境变量 -- 无需您进行任何特殊操作。

【讨论】:

  • 在某些平台上,修改 os.environ 并不会真正修改当前进程或子进程的系统环境。有关更多信息,请参阅文档:docs.python.org/2/library/os.html#os.environ
  • @Evan 可能有一些 Unix 的历史变体不支持putenv(),但对于那些 Unixen,无论如何你都无能为力。甚至我使用的旧版本的 AIX 和 HPUX 也支持它。如果今天真的有人能够找到不支持它的计算机,我非常怀疑他们是否能够在那台计算机上运行 Python。 :)
  • 注意: 引用@Evan 上面的参考资料,对环境的此类更改会影响以 os.system()、popen() 或 fork() 启动的子进程和 execv()。 换句话说,请记住,这种方法不会修改程序的运行方式,只会修改程序子程序的运行方式。诚然,您的程序可以设置和读回环境变量,但只能从它为其子项配置的环境中设置和读取。另请参阅:change current process environment。到目前为止,我还没有找到一种让 Python 脚本修改其父环境的方法。
  • @SvenMarnach 是声明“子进程自动继承父进程的环境”,对于像 bash 这样的 shell。
  • 对于像我这样的菜鸟,您必须先输入import os,否则这将不起作用。
【解决方案2】:

您可能需要进一步考虑代码稳健性的一些方面;

当您将整数值变量存储为环境变量时,请尝试

os.environ['DEBUSSY'] = str(myintvariable)

那么对于检索,考虑到避免错误,你应该尝试

os.environ.get('DEBUSSY', 'Not Set')

可能用“-1”代替“未设置”

所以,把这些放在一起

myintvariable = 1
os.environ['DEBUSSY'] = str(myintvariable)
strauss = int(os.environ.get('STRAUSS', '-1'))
# NB KeyError <=> strauss = os.environ['STRAUSS']
debussy = int(os.environ.get('DEBUSSY', '-1'))

print "%s %u, %s %u" % ('Strauss', strauss, 'Debussy', debussy)

【讨论】:

  • 你能告诉如何在 Linux 机器上设置变量,所有平台的代码都相同吗?
  • 为缺失的整数存储 -1 几乎没有意义。更好的选择是myvar = int(os.environ.get('MYVAR')) if os.environ.get('MYVAR', '') != '' else None——如果没有提供数字,那就是 None
  • 如果你在处理整数,-1 是有意义的。虽然我可能会将变量/常量设置为我将用于未设置的值(例如,value_not_set = '-1')。然后,您可以使用debussy = int(os.environ.get('DEBUSSY', value_not_set))
【解决方案3】:

os.environ 的行为类似于 python 字典,因此可以执行所有常见的字典操作。除了其他答案中提到的getset 操作之外,我们还可以简单地检查是否存在密钥。键和值应存储为字符串

Python 3

对于 python 3,字典使用 in 关键字而不是 has_key

>>> import os
>>> 'HOME' in os.environ  # Check an existing env. variable
True
...

Python 2

>>> import os
>>> os.environ.has_key('HOME')  # Check an existing env. variable
True
>>> os.environ.has_key('FOO')   # Check for a non existing variable
False
>>> os.environ['FOO'] = '1'     # Set a new env. variable (String value)
>>> os.environ.has_key('FOO')
True
>>> os.environ.get('FOO')       # Retrieve the value
'1'

使用os.environ有一件重要的事情需要注意:

虽然子进程继承了父进程的环境,但我最近遇到了一个问题,发现如果你的 python 脚本运行时有其他脚本更新环境,再次调用os.environ不会反映最新的价值观

摘自docs

第一次导入os模块时捕获这个映射, 通常在 Python 启动期间作为处理 site.py 的一部分。变化 到这个时间之后所做的环境都没有体现在 os.environ,直接修改os.environ的改动除外。

os.environ.data存储了所有的环境变量,是一个dict对象,里面包含了所有的环境值:

>>> type(os.environ.data)  # changed to _data since v3.2 (refer comment below)
<type 'dict'>

【讨论】:

  • 进程的环境变量是在创建进程时设置的。在此之后所做的任何更改都不会影响进程自己的环境变量副本。这对所有进程都是通用的,而不仅仅是 Python。此外,os.environ.data 在 Python 3.2 中被重命名为 os.environ._data,下划线前缀表明您不应该直接阅读它。无论如何,os.environ._data 无论如何都不会更新值。
  • 是的,我现在明白了。我想与其他前来寻找的人分享我最初的惊喜。感谢您指出自 3.2 以来对变量名称的更新,将更新答案。
【解决方案4】:

在使用此方法之前,请浏览评论部分

我一直在尝试添加环境变量。我的目标是将一些用户信息存储到系统变量中,以便我可以将这些变量用于未来的解决方案,作为配置文件的替代方案。 但是,下面代码中描述的方法对我一点帮助都没有。

import os
os.environ["variable_1"] = "value_1"
os.environ["variable_2"] = "value_2"
# To Verify above code
os.environ.get("variable_1")
os.environ.get("variable_2")

这个简单的代码块运行良好,但是,这些变量存在于各个进程中,因此您不会在 Windows 系统设置的环境变量选项卡中找到它们。上面的代码几乎没有达到我的目的。这个问题在这里讨论:variable save problem

os.environ.putenv(key, value)

又一次失败的尝试。所以,最后,我通过模仿包装在 os 包的系统类中的 windows shell 命令成功地将变量保存在窗口环境寄存器中。下面的代码描述了这次成功的尝试。

os.system("SETX {0} {1} /M".format(key, value))

我希望这对你们中的一些人有所帮助。

【讨论】:

  • 这是一个非常糟糕的主意!该变量将永久存储在系统中,您只能通过编辑注册表将其删除! (HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment)。当您提出此类建议时,您至少应该警告人们! (但也许你甚至对此一无所知!)
  • 是的,这里的想法是添加一个永久变量。我应该提到这一点。感谢更新。答案开头描述的方法确实添加了仅存在于该进程中的环境变量,这是选择问题,我需要永久保存。
  • 我认为这根本不是这个想法。一方面,这个问题或其描述没有提到任何类似的东西。然后,从逻辑上假设提问者只想创建一个 persistent 变量,可以被其他脚本等使用,而不是注册表中的 permanent 变量!现在,我承认我的评论很激进,但是你让我浪费了很多时间,直到我发现如何从我为测试而创建的环境中删除一个永久变量!!
  • 它实际上比永久注册表存储更糟糕。 setx 可以截断您的环境变量。如果你将它用于像PATH 变量这样重要的东西,当变量超过 1024 个字符时,你的整个现有环境配置将被破坏。也没有办法“撤消”它。不要使用它。甚至微软doesn't know better
【解决方案5】:

如果我做 os.environ["DEBUSSY"] = 1,它 抱怨说 1 必须是 字符串。

那就做吧

os.environ["DEBUSSY"] = "1"

我也想知道怎么读 python中的环境变量(在 脚本的后面部分)一旦我设置 它。

只需使用os.environ["DEBUSSY"],如

some_value = os.environ["DEBUSSY"]

【讨论】:

    【解决方案6】:

    设置变量:

    使用key的item赋值方法:

    import os    
    os.environ['DEBUSSY'] = '1'  #Environ Variable must be string not Int
    

    获取或检查它是否存在,

    因为 os.environ 是一个实例,您可以尝试对象方式。

    方法一:

    os.environ.get('DEBUSSY') # this is error free method if not will return None by default
    

    将得到'1'作为返回值

    方法二:

    os.environ['DEBUSSY'] # will throw an key error if not found!
    

    方法三:

    'DEBUSSY' in os.environ  # will return Boolean True/False
    

    方法四:

    os.environ.has_key('DEBUSSY') #last 2 methods are Boolean Return so can use for conditional statements
    

    【讨论】:

      【解决方案7】:

      os.environ["DEBUSSY"] = '1' 呢?环境变量总是字符串。

      【讨论】:

        【解决方案8】:

        您应该将字符串值分配给环境变量。

        os.environ["DEBUSSY"] = "1"

        如果您想读取或打印环境变量,只需使用

        print os.environ["DEBUSSY"]

        此更改仅对分配它的当前进程有效,不会永久更改值。子进程将自动继承父进程的环境。

        【讨论】:

        • “此更改仅对分配它的当前进程有效,不会永久更改值。”这回答了我关于设置环境变量范围的问题。跨度>
        • 如果我退出python shell,之前设置的os环境就没有了。
        • 如何在windows中设置环境变量?我试过set [&lt;name&gt;=[&lt;value&gt;]],但它只适用于当前正在运行的进程。当我关闭 cmd 时它不存在,即使它打开其他程序也看不到它。
        【解决方案9】:

        应该注意,如果您尝试将环境变量设置为 bash 评估,它不会存储您所期望的。示例:

        from os import environ
        
        environ["JAVA_HOME"] = "$(/usr/libexec/java_home)"
        

        这不会像在 shell 中那样评估它,因此您将获得文字表达式 $(/usr/libexec/java_home),而不是获取 /Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home 作为路径。

        确保在设置环境变量之前对其进行评估,如下所示:

        from os import environ
        from subprocess import Popen, PIPE
        
        bash_variable = "$(/usr/libexec/java_home)"
        capture = Popen(f"echo {bash_variable}", stdout=PIPE, shell=True)
        std_out, std_err = capture.communicate()
        return_code = capture.returncode
        
        if return_code == 0:
            evaluated_env = std_out.decode().strip()
            environ["JAVA_HOME"] = evaluated_env
        else:
            print(f"Error: Unable to find environment variable {bash_variable}")
        

        【讨论】:

          【解决方案10】:

          您可以使用os.environ 字典来访问您的环境变量。

          现在,我遇到的一个问题是,如果我尝试使用 os.system 运行设置环境变量的批处理文件(在 **.bat* 文件中使用 SET 命令),它不会真正将它们设置为您的 python 环境(但对于使用 os.system 函数创建的子进程)。为了实际获取python环境中设置的变量,我使用了这个脚本:

          import re
          import system
          import os
          
          def setEnvBat(batFilePath, verbose = False):
              SetEnvPattern = re.compile("set (\w+)(?:=)(.*)$", re.MULTILINE)
              SetEnvFile = open(batFilePath, "r")
              SetEnvText = SetEnvFile.read()
              SetEnvMatchList = re.findall(SetEnvPattern, SetEnvText)
          
              for SetEnvMatch in SetEnvMatchList:
                  VarName=SetEnvMatch[0]
                  VarValue=SetEnvMatch[1]
                  if verbose:
                      print "%s=%s"%(VarName,VarValue)
                  os.environ[VarName]=VarValue
          

          【讨论】:

            【解决方案11】:

            当您使用环境变量(添加/修改/删除变量)时,一个好的做法是在函数完成时恢复之前的状态。

            您可能需要类似 question 中描述的 modified_environ 上下文管理器来恢复环境变量。

            经典用法:

            with modified_environ(DEBUSSY="1"):
                call_my_function()
            

            【讨论】:

              【解决方案12】:

              如果环境中不存在变量,使用setdefault函数设置新变量。

              确保将环境变量设置为字符串,而不是 int。否则会抛出TypeError

              import os
              
              if not os.environ.get("DEBUSSY"):
                  os.environ.setdefault("DEBUSSY","1")
              else:
                   os.environ["DEBUSSY"] = "1"
              
              print(os.environ["DEBUSSY"])
              
              

              【讨论】:

              • 你根本不需要 if 语句吗?我认为仅使用setdefault 方法就足够了。
              【解决方案13】:

              有一个很好的开箱即用的 Python 解决方案,称为 pycrosskit。 它将创建对 Linux 和 Windows 都是持久的环境变量。

              用法:

              # Will Set Persistent Value for Variable in System
              # * subkey works only for windows like file in folder
              # * reg_path works only for windows as register path 
              SysEnv.set_var(name, value, subkey, reg_path=default_reg_path)
              
              # Will Get Persistent Value for Variable in System
              # * reg_path works only for windows as register path
              # * delete, deletes key from environment and its subkeys after read
              SysEnv.get_var(name, reg_path=default_reg_path, delete=False)
              

              【讨论】:

              • 这样创建的环境变量似乎根本就不是持久化的。
              【解决方案14】:

              如果您在使用 Flask 和 unittest 时遇到困难,请记住,如果您在任何方法之外设置变量,则在导入应用程序时会读取此变量。可能看起来微不足道,但可以避免一些人头疼。

              例如,如果进入你的 Flask 单元测试你:

              1. 导入应用
              2. setUp方法中设置环境变量。
              3. 使用app.test_client() 测试您的应用程序

              进入第二步的变量不会被第三步看到,因为当你执行第一步时,变量已经被读取了。

              【讨论】:

                【解决方案15】:

                我写了这个简洁的小context manager 用于设置仅在缩进块期间的变量:

                import os
                from contextlib import contextmanager
                
                @contextmanager
                def extended_env(new_env_vars):
                    old_env = os.environ.copy()
                    os.environ.update(new_env_vars)
                    yield
                    os.environ.clear()
                    os.environ.update(old_env)
                

                使用示例(希望是跨平台的):

                import subprocess
                
                subprocess.run("echo $ENVTESTO %ENVTESTO%", shell=True)
                
                with extended_env({"ENVTESTO": "17"}):
                    subprocess.run("echo $ENVTESTO %ENVTESTO%", shell=True)
                
                subprocess.run("echo $ENVTESTO %ENVTESTO%", shell=True)
                

                【讨论】: