Python 环境变量以及如何使用它们

是否想要更有效地管理你的配置?探索如何在Python中运用环境变量。

在自学Python的过程中,我通过构建项目来实践所学。其中一项任务是连接数据库并使用Python进行查询。这意味着我需要存储数据库的配置信息和敏感数据,比如用于身份验证的用户名和密码。

将此类敏感信息硬编码到Python脚本中显然不是一个好主意。我还学习了如何使用配置文件和环境变量,以及如何通过Python的内置模块来操作它们。

因此,每当需要在应用中使用密码和API密钥等敏感信息时,我都会将它们设置为环境变量,并根据需要提取。在本教程中,我将指导你了解环境变量及其在Python中的应用。

什么是环境变量?

环境变量是存在于应用程序外部的变量,用来存储配置信息、系统设置等。它们通常由操作系统或应用程序环境进行管理。环境变量的关键特点包括:

  • 键值对:环境变量由名称(也称作键)和对应的值构成。
  • 系统级范围:环境变量可以在系统级别设置,使得系统上运行的所有进程都可以访问。当然,你也可以在应用程序级别修改或定义它们,仅影响特定的应用程序。
  • 动态和可变:环境变量可以在运行时被修改,提供极大的灵活性。

环境变量的益处

环境变量在管理Python应用中的配置信息和敏感数据方面有诸多好处:

  • 关注点分离:通过将配置存储在代码之外,你可以将配置管理与应用程序逻辑分离。
  • 安全性:你可以将API密钥和数据库凭证等敏感数据保存在环境变量中,避免直接暴露在源代码中,从而降低安全风险。
  • 灵活性:使用环境变量,更新配置设置非常简单,你可以在代码库之外进行更改。环境变量允许你调整配置,而无需修改代码。这种灵活性在将应用部署到不同环境或更新凭证时尤为重要。

在本教程接下来的部分,我们将探讨如何在Python中设置、访问和管理环境变量,以及它们如何提升项目中的配置管理水平。

如何设置环境变量

你可以使用命令行设置环境变量。这种方式设置的环境变量仅限于当前会话,不会在会话结束后保留。

如果你使用的是Mac或Linux电脑,你可以在当前终端会话中通过以下方式设置环境变量:

export MY_VARIABLE=my_value

如果你是Windows用户,你可以通过以下方式临时设置环境变量:

set MY_VARIABLE=my_value

在Python中访问环境变量

Python提供了os模块用于执行与操作系统相关的功能。os.environ是一个存储环境变量的字典。环境变量的名称及其值分别是字典的键和值。

因此,你可以通过使用环境变量的名称作为键来访问它们的值,就像访问字典元素一样。

以下是一些示例:

import os
print(os.environ['HOME'])
# Output: /home/balapriya
print(os.environ['USER'])
# Output: balapriya

到目前为止一切顺利。但是,如果你尝试访问一个未设置的环境变量的值,会发生什么?

让我们尝试访问一个我们尚未设置的API_KEY:

print(os.environ['API_KEY'])

正如预期的,你会得到一个KeyError:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<frozen os>", line 679, in __getitem__
KeyError: 'API_KEY'

处理KeyError

你可以通过以下方式处理KeyError:

import os

try:
	api_key = os.environ['API_KEY']
	print(f'API_KEY is set to: {api_key}')
except KeyError:
	print('API_KEY is not set. Please configure it.')

此方法不会使程序在引发KeyError异常时立即停止运行,而是会提供一条描述性的错误消息:

# Output
API_KEY is not set. Please configure it.

这样,当程序的其他部分未按预期工作时,我们就知道是缺少了必要的环境变量设置。

使用get()方法访问环境变量

你可以使用字典的get()方法来获取环境变量的值。如果未找到变量,get()方法会返回None,而不是抛出KeyError。

访问一个我们尚未设置的NOT_SET变量不会返回KeyError,而是None

print(os.environ.get('NOT_SET'))
# Output: None

我个人更倾向于在未设置环境变量时引发KeyError,而不是让它默默地传递或包含在get()方法返回的None中。

但是,当我们需要为特定环境变量提供默认值(如果未设置)时,get()方法会非常有用。

以下是一个示例:

print(os.environ.get('HOME','/home/user'))
# Output: /home/balapriya

如何使用环境变量管理配置

现在让我们来看几个在应用程序中使用环境变量的实际示例。

示例1:配置数据库连接参数

假设你想从Python连接到PostgreSQL数据库。为此,你可以安装并使用psycopg2连接器:

pip install psycopg2

在本例中,我们使用环境变量来配置数据库连接参数。如果环境变量未设置,我们会提供默认值:

import os
import psycopg2  

# 从环境变量中检索数据库配置
db_host = os.environ.get('DB_HOST', 'localhost')
db_port = os.environ.get('DB_PORT', '5432')
db_user = os.environ.get('DB_USER', 'myuser')
db_password = os.environ.get('DB_PASSWORD', 'mypassword')

# 建立数据库连接
try:
	connection = psycopg2.connect(
    	host=db_host,
    	port=db_port,
    	user=db_user,
    	password=db_password,
    	database="mydb"
	)
	print('Connected to the database!')
except Exception as e:
	print(f'Error connecting to the database: {e}')

示例 2:管理 API 密钥

我们再来看一个涉及使用API密钥的例子。

除了ChatGPT界面之外,你还可以使用OpenAI API在你的应用中启用OpenAI LLM。

当你注册OpenAI帐户时,你(通常会看到)获得一些免费的限时API积分。通过导航到“设置”>“查看API密钥”来获取你的API密钥。

你可以使用Open AI Python SDK和LangChain等框架来构建应用。为此,你需要使用pip安装库(在虚拟环境中):

pip install openai
pip install langchain 

以下是将OPENAI_API_KEY设置为环境变量的方法:

import os
os.environ["OPENAI_API_KEY"]='your-api-key'

你现在可以在脚本中访问Open AI LLM,如下所示:

from langchain.llms import OpenAI
model=OpenAI(model_name="gpt-3.5-turbo")

如何在Python中修改环境变量

你可以通过访问os模块中的os.environ字典来修改当前Python进程中的环境变量:

import os

# 修改一个已存在的环境变量或创建一个新的
os.environ['MY_VARIABLE'] = 'new_value'

在Python中,你可以使用subprocess模块从现有的Python脚本创建子进程。当你需要在Python中执行系统程序时,这很有帮助。

在下面的示例中,我们通过利用os.environ字典来修改PATH环境变量。然后我们将echo $PATH作为子进程运行:

import os
import subprocess

# 为子进程设置自定义环境变量
os.environ['PATH'] = '/custom/path'

# 运行一个访问PATH环境变量的子进程
result = subprocess.run("echo $PATH", shell=True, stdout=subprocess.PIPE)
output = result.stdout.decode()
print(output)
print(f'Subprocess output: {output}')

我们看到PATH的值为/custom/path

# Output
/custom/path

修改环境变量的作用域

需要注意的是,这些环境变量的更新是临时的,只对当前的Python进程有效。脚本结束后,所做的更改将会被丢弃:

  • 当前Python进程:当你在Python脚本中使用os.environ修改环境变量时,所做的更改仅在当前Python进程中有效。它不会影响其他正在运行的进程或未来的Python会话。
  • 子进程:当前Python进程中所做的环境变量更改将由脚本创建的子进程继承。例如,如果你从Python脚本(父进程)创建子进程,则子进程将有权访问修改后的环境变量(如示例所示)。
  • 非系统范围:在Python脚本中设置的环境变量不会在该脚本执行之外保留。

如果你需要在系统级别对环境变量进行持久更改,通常需要使用操作系统特定的方法来实现。

如何使用python-dotenv加载.env文件

python-dotenv库是一个流行的Python包,它简化了将环境变量从.env文件加载到Python项目中的过程。当你拥有多个具有不同配置的环境(例如,开发、生产)并且你希望将这些设置与源代码分离时,它特别有用。

安装python-dotenv

要使用python-dotenv,你需要先安装它。你可以使用Python包管理器pip在虚拟环境中安装它:

pip install python-dotenv

从.env文件加载环境变量

现在,你可以在项目的根目录中创建一个名为.env的文件,并使用键值对填充它,就像常规的环境变量一样。让我们用占位符值创建一个如下的.env文件:

API_KEY=your_api_key_here
DB_PASSWORD=your_database_password_here

你现在可以使用python-dotenv从.env文件加载环境变量,如下所示:

import os
from dotenv import load_dotenv

# 从.env文件加载环境变量
load_dotenv()

# 访问环境变量
api_key = os.getenv("API_KEY")
database_password = os.getenv("DB_PASSWORD")

# 输出环境变量
print(f"API Key: {api_key}")
print(f"Database Password: {database_password}")

请注意,我们使用os.getenv(VARIABLE_NAME)来获取环境变量的值。这也是一种访问环境变量的有效(且不太常用的)方式。

以下是输出结果:

API Key: your-api-key-here
Database Password: your-database-url-here

在这个例子中:

  • 我们使用load_dotenv().env文件中定义的环境变量加载到当前环境中。
  • 然后我们使用os.getenv()来访问环境变量:API_KEYDB_PASSWORD

结论

就这样了!希望你已经了解了如何在Python应用中使用环境变量来管理配置和敏感信息。我们介绍了设置和访问环境变量的基础知识,以及它们在配置应用程序中的实际用途。

虽然环境变量有助于将配置与源代码分离,但你仍然应该在生产环境中将敏感变量存储为秘密。为了管理秘密,我建议你探索诸如HashiCorp Vault 或者 AWS Secret Manager之类的工具。