跳到内容

虚拟环境

在 Python 项目中工作时,你可能应该使用 虚拟环境 (或类似机制)来隔离你为每个项目安装的包。

信息

如果你已经了解虚拟环境,知道如何创建和使用它们,你可能想跳过本节。 🤓

提示

一个 虚拟环境环境变量 不同。

一个 环境变量 是系统中可以被程序使用的一个变量。

一个 虚拟环境 是一个包含一些文件的目录。

信息

本页将教你如何使用 虚拟环境 以及它们的工作原理。

如果你准备采用一个 管理一切的工具 (包括安装 Python),请尝试 uv

创建项目

首先,为你的项目创建一个目录。

我通常的做法是在我的主/用户目录下创建一个名为 code 的目录。

然后在其中为每个项目创建一个目录。

// Go to the home directory
$ cd
// Create a directory for all your code projects
$ mkdir code
// Enter into that code directory
$ cd code
// Create a directory for this project
$ mkdir awesome-project
// Enter into that project directory
$ cd awesome-project

创建虚拟环境

当你 首次 开始处理一个 Python 项目时,在 你的项目内 创建一个虚拟环境。

提示

你只需要 每个项目做一次 ,而不是每次工作时都做。

要创建虚拟环境,你可以使用 Python 自带的 venv 模块。

$ python -m venv .venv
该命令的含义
  • python:使用名为 python 的程序
  • -m:将模块作为脚本调用,接下来我们会告诉它使用哪个模块
  • venv:使用名为 venv 的模块,该模块通常随 Python 一起安装
  • .venv:在新目录 .venv 中创建虚拟环境

如果你安装了 uv,你可以使用它来创建虚拟环境。

$ uv venv

提示

默认情况下,uv 将在一个名为 .venv 的目录中创建一个虚拟环境。

但你可以通过传递一个包含目录名称的额外参数来对其进行自定义。

该命令在一个名为 .venv 的目录中创建一个新的虚拟环境。

.venv 或其他名称

你可以在不同的目录中创建虚拟环境,但约定俗成是将其命名为 .venv

激活虚拟环境

激活新的虚拟环境,以便你运行的任何 Python 命令或安装的包都使用它。

提示

每次 你启动 新的终端会话 以处理项目时,执行此操作。

$ source .venv/bin/activate
$ .venv\Scripts\Activate.ps1

或者如果你使用适用于 Windows 的 Bash(例如 Git Bash

$ source .venv/Scripts/activate

提示

每次你在该环境中安装 新包 时,请再次 激活 环境。

这确保了如果你使用该包安装的 终端(CLI)程序,你使用的是来自你的虚拟环境中的程序,而不是任何可能全局安装的程序,这些全局程序可能与你需要的版本不同。

检查虚拟环境是否激活

检查虚拟环境是否激活(前面的命令已起作用)。

提示

这是 可选的,但这是个很好的方法来 检查 一切是否按预期工作,以及你是否正在使用你打算使用的虚拟环境。

$ which python

/home/user/code/awesome-project/.venv/bin/python

如果它显示 python 二进制文件位于 .venv/bin/python,在你的项目内部(本例中为 awesome-project),那么它就成功了。 🎉

$ Get-Command python

C:\Users\user\code\awesome-project\.venv\Scripts\python

如果它显示 python 二进制文件位于 .venv\Scripts\python,在你的项目内部(本例中为 awesome-project),那么它就成功了。 🎉

升级 pip

提示

如果你使用 uv 来安装东西而不是 pip,那么你不需要升级 pip。 😎

如果你正在使用 pip 安装包(Python 默认自带),你应该 升级 它到最新版本。

安装包时出现的许多奇怪错误,通常通过先升级 pip 即可解决。

提示

你通常只需要 做一次,就在你创建虚拟环境之后。

确保虚拟环境已激活(使用上面的命令),然后运行

$ python -m pip install --upgrade pip

---> 100%

添加 .gitignore

如果你正在使用 Git (你应该使用),添加一个 .gitignore 文件,将你 .venv 目录中的所有内容从 Git 中排除。

提示

如果你使用 uv 创建虚拟环境,它已经为你完成了这一步,你可以跳过此步骤。 😎

提示

只做 一次,就在你创建虚拟环境之后。

$ echo "*" > .venv/.gitignore
该命令的含义
  • echo "*":将在终端中“打印”文本 * (下一部分会稍微改变这一点)
  • >:左侧命令打印到终端的任何内容不应打印,而应写入 > 右侧的文件中
  • .gitignore:应该写入文本的文件名

* 对于 Git 来说意味着“一切”。因此,它将忽略 .venv 目录中的所有内容。

该命令将创建一个名为 .gitignore 的文件,内容如下

*

安装包

激活环境后,你可以在其中安装包。

提示

在安装或升级项目所需包时, 只做一次

如果你需要升级版本或添加新包,你将 再次执行此操作

直接安装包

如果你赶时间,不想使用文件来声明项目所需的包,你可以直接安装它们。

提示

将程序所需的包及其版本放在一个文件(例如 requirements.txtpyproject.toml)中是一个(非常)好的主意。

$ pip install "fastapi[standard]"

---> 100%

如果你有 uv

$ uv pip install "fastapi[standard]"
---> 100%

requirements.txt 安装

如果你有一个 requirements.txt 文件,你现在可以使用它来安装其包。

$ pip install -r requirements.txt
---> 100%

如果你有 uv

$ uv pip install -r requirements.txt
---> 100%
requirements.txt

一个 requirements.txt 包含一些包的示例可能如下所示

fastapi[standard]==0.113.0
pydantic==2.8.0

运行你的程序

激活虚拟环境后,你可以运行你的程序,它将使用虚拟环境中的 Python 以及你在其中安装的包。

$ python main.py

Hello World

配置你的编辑器

你可能会使用一个编辑器,请确保你配置它使用你创建的虚拟环境(它可能会自动检测),以便你可以获得自动补全和行内错误提示。

例如:

提示

你通常只需要 做一次,即在你创建虚拟环境时。

停用虚拟环境

完成项目工作后,你可以 停用 虚拟环境。

$ deactivate

这样一来,当你运行 python 时,它就不会尝试从该虚拟环境及其安装的包中运行。

准备好工作

现在你已经准备好开始你的项目工作了。

提示

你想理解上面所有这些是什么吗?

继续阅读。 👇🤓

为什么使用虚拟环境

要使用 FastAPI,你需要安装 Python

之后,你需要 安装 FastAPI 和任何其他你想要使用的

要安装包,你通常会使用 Python 自带的 pip 命令(或类似替代方案)。

然而,如果你直接使用 pip,包将被安装在你的 全局 Python 环境 (Python 的全局安装)中。

问题

那么,将包安装在全局 Python 环境中有什么问题呢?

在某个时候,你可能会编写许多依赖于 不同包 的程序。你正在处理的某些项目将依赖于同一包的 不同版本。 😱

例如,你可以创建一个名为 philosophers-stone 的项目,该程序依赖于另一个名为 harry 的包,使用版本 1。因此,你需要安装 harry

flowchart LR
    stone(philosophers-stone) -->|requires| harry-1[harry v1]

然后,在稍后的某个时候,你创建了另一个名为 prisoner-of-azkaban 的项目,该项目也依赖于 harry,但该项目需要 harry 版本 3

flowchart LR
    azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3]

但现在的问题是,如果你将包全局安装(在全局环境中)而不是在本地 虚拟环境 中安装,你将不得不选择安装哪个版本的 harry

如果你想运行 philosophers-stone,你需要首先安装 harry 版本 1,例如使用

$ pip install "harry==1"

然后你的全局 Python 环境中将安装 harry 版本 1

flowchart LR
    subgraph global[global env]
        harry-1[harry v1]
    end
    subgraph stone-project[philosophers-stone project]
        stone(philosophers-stone) -->|requires| harry-1
    end

但是,如果你想运行 prisoner-of-azkaban,你需要卸载 harry 版本 1 并安装 harry 版本 3 (或者直接安装版本 3 会自动卸载版本 1)。

$ pip install "harry==3"

然后你的全局 Python 环境中将安装 harry 版本 3

如果你再次尝试运行 philosophers-stone,它很可能 无法工作,因为它需要 harry 版本 1

flowchart LR
    subgraph global[global env]
        harry-1[<strike>harry v1</strike>]
        style harry-1 fill:#ccc,stroke-dasharray: 5 5
        harry-3[harry v3]
    end
    subgraph stone-project[philosophers-stone project]
        stone(philosophers-stone) -.-x|⛔️| harry-1
    end
    subgraph azkaban-project[prisoner-of-azkaban project]
        azkaban(prisoner-of-azkaban) --> |requires| harry-3
    end

提示

Python 包通常会尽力 避免在破坏性更改 中引入 新版本,但为了安全起见,最好在能够运行测试检查一切正常时,有意识地安装新版本。

现在,想象一下你的所有 项目都依赖于 许多 其他 。这非常难以管理。你很可能最终会运行某些项目,其中包的 不兼容版本,并且不知道为什么某些东西无法工作。

此外,根据你的操作系统(例如 Linux、Windows、macOS),它可能已经预装了 Python。在这种情况下,它可能预装了一些特定版本的包,这些包是 系统所需的。如果你在全局 Python 环境中安装包,你可能会 破坏 操作系统自带的一些程序。

包安装在哪里

当你安装 Python 时,它会在你的计算机中创建一些包含文件的目录。

其中一些目录负责存放你安装的所有包。

当你运行

// Don't run this now, it's just an example 🤓
$ pip install "fastapi[standard]"
---> 100%

这将下载一个包含 FastAPI 代码的压缩文件,通常来自 PyPI

它还会 下载 FastAPI 依赖的其他包的文件。

然后它会 解压 所有这些文件,并将它们放在你的计算机上的一个目录中。

默认情况下,它会将下载和解压的文件放在随 Python 安装附带的目录中,这就是 全局环境

什么是虚拟环境

解决所有包都位于全局环境中的问题的方法是,为你工作的每个项目使用一个 虚拟环境

虚拟环境是一个 目录,与全局目录非常相似,你可以在其中安装项目的包。

这样,每个项目都将拥有自己的虚拟环境(.venv 目录),其中包含自己的包。

flowchart TB
    subgraph stone-project[philosophers-stone project]
        stone(philosophers-stone) --->|requires| harry-1
        subgraph venv1[.venv]
            harry-1[harry v1]
        end
    end
    subgraph azkaban-project[prisoner-of-azkaban project]
        azkaban(prisoner-of-azkaban) --->|requires| harry-3
        subgraph venv2[.venv]
            harry-3[harry v3]
        end
    end
    stone-project ~~~ azkaban-project

激活虚拟环境意味着什么

当你激活虚拟环境时,例如使用

$ source .venv/bin/activate
$ .venv\Scripts\Activate.ps1

或者如果你使用适用于 Windows 的 Bash(例如 Git Bash

$ source .venv/Scripts/activate

该命令将创建或修改一些 环境变量,这些变量将可用于后续命令。

其中一个变量是 PATH 变量。

提示

你可以在 环境变量 章节中了解更多关于 PATH 环境变量的信息。

激活虚拟环境会将其路径 .venv/bin (在 Linux 和 macOS 上)或 .venv\Scripts (在 Windows 上)添加到 PATH 环境变量中。

假设在激活环境之前,PATH 变量是这样的

/usr/bin:/bin:/usr/sbin:/sbin

这意味着系统会在以下位置查找程序

  • /usr/bin
  • /bin
  • /usr/sbin
  • /sbin
C:\Windows\System32

这意味着系统会在以下位置查找程序

  • C:\Windows\System32

激活虚拟环境后,PATH 变量会变成这样

/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin

这意味着系统现在会首先在以下位置查找程序

/home/user/code/awesome-project/.venv/bin

然后才查找其他目录。

因此,当你在终端中输入 python 时,系统将在以下位置找到 Python 程序

/home/user/code/awesome-project/.venv/bin/python

并使用该程序。

C:\Users\user\code\awesome-project\.venv\Scripts;C:\Windows\System32

这意味着系统现在会首先在以下位置查找程序

C:\Users\user\code\awesome-project\.venv\Scripts

然后才查找其他目录。

因此,当你在终端中输入 python 时,系统将在以下位置找到 Python 程序

C:\Users\user\code\awesome-project\.venv\Scripts\python

并使用该程序。

一个重要的细节是,它会将虚拟环境路径放在 PATH 变量的 开头。系统会 优先于 找到任何其他可用的 Python。这样,当你运行 python 时,它将使用 来自虚拟环境的 Python,而不是任何其他 python (例如,来自全局环境的 python)。

激活虚拟环境还会改变其他一些东西,但这是它所做的最重要的事情之一。

检查虚拟环境

当你检查虚拟环境是否激活时,例如使用

$ which python

/home/user/code/awesome-project/.venv/bin/python
$ Get-Command python

C:\Users\user\code\awesome-project\.venv\Scripts\python

这意味着将使用的 python 程序是 虚拟环境中的

你在 Linux 和 macOS 中使用 which,在 Windows PowerShell 中使用 Get-Command

该命令的工作原理是,它会去检查 PATH 环境变量, 按顺序 遍历每个路径,查找名为 python 的程序。一旦找到它,它会 显示该程序的路径

最重要的部分是,当你调用 python 时,执行的正是该“python”。

因此,你可以确认自己是否在正确的虚拟环境中。

提示

很容易激活一个虚拟环境,获得一个 Python,然后 切换到另一个项目

而第二个项目 将无法工作,因为你正在使用来自另一个项目的虚拟环境中的 错误 Python

能够检查正在使用哪个 python 是很有用的。 🤓

为什么要停用虚拟环境

例如,你可能正在处理项目 philosophers-stone激活该虚拟环境,安装包并在该环境中使用。

然后你想处理 另一个项目 prisoner-of-azkaban

你进入该项目

$ cd ~/code/prisoner-of-azkaban

如果你不停用 philosophers-stone 的虚拟环境,当你在终端中运行 python 时,它将尝试使用来自 philosophers-stone 的 Python。

$ cd ~/code/prisoner-of-azkaban

$ python main.py

// Error importing sirius, it's not installed 😱
Traceback (most recent call last):
    File "main.py", line 1, in <module>
        import sirius

但如果你停用当前虚拟环境并激活 prisoner-of-askaban 的虚拟环境,那么当你运行 python 时,它将使用来自 prisoner-of-azkaban 虚拟环境中的 Python。

$ cd ~/code/prisoner-of-azkaban

// You don't need to be in the old directory to deactivate, you can do it wherever you are, even after going to the other project 😎
$ deactivate

// Activate the virtual environment in prisoner-of-azkaban/.venv 🚀
$ source .venv/bin/activate

// Now when you run python, it will find the package sirius installed in this virtual environment ✨
$ python main.py

I solemnly swear 🐺

替代方案

这是一个简单的指南,旨在帮助你入门并教授你所有工作原理的 底层细节

有许多 替代方案 用于管理虚拟环境、包依赖(需求)和项目。

一旦你准备好并想使用一个工具来 管理整个项目、包依赖、虚拟环境等,我建议你尝试 uv

uv 可以做很多事情,它可以

  • 为你安装 Python,包括不同版本
  • 管理你的项目的 虚拟环境
  • 安装
  • 管理你的项目的包的 依赖和版本
  • 确保你拥有要安装的 精确 一组包和版本,包括它们的依赖项,这样你就可以确保在开发时在你的计算机上运行的项目在生产环境中也能完全相同地运行,这被称为 锁定
  • 以及许多其他事情

结论

如果你阅读并理解了所有这些,那么现在 你了解的更多了 关于虚拟环境的知识比许多开发者都多。 🤓

了解这些细节很可能在未来某个你调试看似复杂的问题时很有用,因为你将知道 所有这些在底层是如何工作的。 😎