跳到内容

虚拟环境

当你从事 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:使用通常随 Python 一起安装的 venv 模块
  • .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 可执行文件在你的项目内部(在本例中为 awesome-project)的 .venv/bin/python,那么它就成功了。🎉

$ Get-Command python

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

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

升级 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 sqlmodel

---> 100%

如果你有 uv

$ uv pip install sqlmodel
---> 100%

requirements.txt 安装

如果你有 requirements.txt,现在可以使用它来安装其中的包。

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

如果你有 uv

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

一个包含一些包的 requirements.txt 可能看起来像

sqlmodel==0.13.0
rich==13.7.1

运行你的程序

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

$ python main.py

Hello World

配置你的编辑器

你可能会使用编辑器,确保将其配置为使用你创建的相同虚拟环境(它可能会自动检测到),以便你可以获得自动补全和内联错误。

例如

提示

你通常只需要在创建虚拟环境时**一次性**执行此操作。

停用虚拟环境

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

$ deactivate

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

准备工作

现在你已准备好开始你的项目。

提示

你想了解上面所有的一切吗?

继续阅读。👇🤓

为什么选择虚拟环境

要使用 SQLModel,你需要安装 Python

之后,你需要**安装** SQLModel 和你想要使用的任何其他**包**。

要安装包,你通常会使用 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 sqlmodel
---> 100%

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

它还将**下载** SQLModel 依赖的其他包的文件。

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

默认情况下,它会将这些下载和解压的文件放在你的 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 时,系统将在

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

找到 Python 程序并使用它。

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

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

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

然后再在其他目录中查找。

因此,当你在终端中输入 python 时,系统将在

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

找到 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**,包括不同的版本
  • 管理你项目的**虚拟环境**
  • 安装**包**
  • 管理你项目的包**依赖和版本**
  • 确保你拥有一组**精确**的包和版本进行安装,包括它们的依赖,这样你就可以确保在生产环境中运行项目与在开发计算机上完全相同,这称为**锁定**
  • 以及许多其他事情

总结

如果你阅读并理解了所有这些内容,那么你现在对虚拟环境的了解**比许多开发人员都多**。🤓

了解这些细节很可能在将来调试一些看起来复杂的问题时派上用场,但你将了解**这一切在底层是如何工作的**。😎