MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Python使用pipenv管理虚拟环境与依赖

2023-06-213.9k 阅读

一、pipenv 简介

在 Python 开发中,管理项目的虚拟环境和依赖关系是至关重要的。虚拟环境允许我们在同一台机器上为不同的项目创建隔离的 Python 环境,每个环境可以有自己独立的 Python 版本和安装的包版本。依赖关系则定义了项目运行所需要的各种包及其特定版本。

pipenv 是一个现代的命令行工具,它结合了 pip(Python 的包管理工具)和 virtualenv(创建和管理虚拟环境的工具)的功能,提供了一种简单且强大的方式来管理 Python 项目的虚拟环境和依赖。它旨在简化项目依赖管理的工作流程,减少因包版本冲突而导致的问题。

二、安装 pipenv

在开始使用 pipenv 之前,需要先将其安装。pipenv 可以通过 pip 进行安装。确保你已经安装了 Python 和 pip,如果你的系统中安装了多个 Python 版本,要注意使用正确版本对应的 pip

在命令行中运行以下命令来安装 pipenv:

pip install pipenv

如果你使用的是 Python 3.7 及以上版本,并且系统支持,也可以使用 pip3 来安装:

pip3 install pipenv

安装完成后,可以通过以下命令检查 pipenv 是否安装成功:

pipenv --version

如果安装成功,会显示 pipenv 的版本号。

三、创建虚拟环境

  1. 基本创建
    • 在项目目录下创建虚拟环境是一种常见的做法。首先,打开命令行,导航到你想要创建项目的目录。例如,假设我们要在 my_project 目录下创建项目和虚拟环境:
mkdir my_project
cd my_project
pipenv install
  • 上述 pipenv install 命令会在当前目录下创建一个新的虚拟环境,并同时生成一个 Pipfile 文件。Pipfile 用于记录项目的依赖关系。如果当前目录下已经存在 Pipfilepipenv install 会根据 Pipfile 中的内容安装依赖。
  1. 指定 Python 版本
    • 有时候,项目需要特定版本的 Python。pipenv 可以很方便地指定创建虚拟环境所使用的 Python 版本。例如,要创建一个使用 Python 3.8 的虚拟环境:
pipenv install --python 3.8
  • 如果你的系统中安装了指定版本的 Python,pipenv 会基于该版本创建虚拟环境。如果没有安装指定版本的 Python,可能需要先安装相应版本的 Python 才能成功创建。

四、Pipfile 和 Pipfile.lock

  1. Pipfile
    • 结构和作用Pipfile 是 pipenv 用于管理项目依赖的核心文件。它采用了一种类似 TOML(Tom's Obvious, Minimal Language)的格式。在 Pipfile 中,有两个主要的部分:[packages][dev-packages]
      • [packages] 部分用于列出项目运行所需要的包及其版本。例如:
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[packages]
requests = "*"
flask = "~=1.1.2"

在这个例子中,requests 包使用任意版本(* 表示任意版本),而 flask 包使用与 1.1.2 兼容的版本(~= 表示兼容版本,具体来说,它会安装主版本和次版本相同的最新版本,这里就是 1.1.x 系列的最新版本)。 - [dev-packages] 部分用于列出开发过程中需要的包,比如测试框架、代码检查工具等。例如:

[dev-packages]
pytest = "^6.0.1"
flake8 = "*"

这里 pytest 包使用版本 6.0.1 及以上的版本(^ 表示语义化版本控制,它会安装主版本相同的最新版本,这里就是 6.x 系列的最新版本),flake8 使用任意版本。

  • 手动编辑:虽然 pipenv 会在安装和卸载包时自动更新 Pipfile,但也可以手动编辑它。例如,如果想更改某个包的版本,可以直接在 Pipfile 中修改相应的版本号,然后运行 pipenv install 来更新实际安装的包版本。
  1. Pipfile.lock
    • 生成和作用Pipfile.lockpipenv 生成的一个文件,用于锁定项目依赖的精确版本。当运行 pipenv install 时,pipenv 会根据 Pipfile 解析出所有依赖包及其版本,并将这些信息精确地记录在 Pipfile.lock 中。例如,对于上述 Pipfile 中的依赖,Pipfile.lock 可能会包含如下内容(简化示例):
{
    "_meta": {
        "hash": {
            "sha256": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2g3h4i5j6k7l8m9n0o1p2q3r4s5t6u7v8w9x0y1z2a3b4c5d6e7f8g9h0i1j2k3l4m5n6o7p8q9r0s1t2u3v4w5x6y7z8a9b0c1d2e3f4g5h6i7j8k9l0m1n2o3p4q5r6s7t8u9v0w1x2y3z4a5b6c7d8e9f0g1h2i3j4k5l6m7n8o9p0q1r2s3t4u5v6w7x8y9z0a1b2c3d4e5f6"
        },
        "pipfile-spec": 6,
        "requires": {},
        "sources": [
            {
                "name": "pypi",
                "url": "https://pypi.org/simple",
                "verify_ssl": true
            }
        ]
    },
    "default": {
        "flask": {
            "hashes": [
                "sha256:abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
                "sha256:0987654321fedcba0987654321fedcba0987654321fedcba0987654321fedcba"
            ],
            "index": "pypi",
            "version": "==1.1.2"
        },
        "requests": {
            "hashes": [
                "sha256:131231231231231231231231231231231231231231231231231231231231231231",
                "sha256:234234234234234234234234234234234234234234234234234234234234234234"
            ],
            "index": "pypi",
            "version": "==2.25.1"
        }
    },
    "develop": {
        "flake8": {
            "hashes": [
                "sha256:567567567567567567567567567567567567567567567567567567567567567567",
                "sha256:678678678678678678678678678678678678678678678678678678678678678678"
            ],
            "index": "pypi",
            "version": "==3.8.4"
        },
        "pytest": {
            "hashes": [
                "sha256:789789789789789789789789789789789789789789789789789789789789789789",
                "sha256:890890890890890890890890890890890890890890890890890890890890890890"
            ],
            "index": "pypi",
            "version": "==6.0.1"
        }
    }
}
  • 重要性Pipfile.lock 确保了项目在不同环境(如开发、测试、生产环境)中安装的依赖包版本完全一致。当在新环境中运行 pipenv install 时,pipenv 会优先读取 Pipfile.lock 中的精确版本信息来安装包,而不是仅根据 Pipfile 中的版本约束去解析最新版本。这有助于避免因包版本更新而导致的兼容性问题。

五、安装和管理依赖

  1. 安装包
    • 安装普通包:要安装项目运行所需的包,可以使用 pipenv install 命令,后面跟上包名。例如,要安装 numpy 包:
pipenv install numpy
  • 上述命令会将 numpy 包安装到当前项目的虚拟环境中,并在 Pipfile[packages] 部分添加相应的记录。如果 numpy 有依赖其他包,pipenv 会自动安装这些依赖包,并在 PipfilePipfile.lock 中记录相关信息。
  • 安装开发包:对于开发过程中使用的包,如测试框架、代码格式化工具等,可以使用 pipenv install --dev 命令。例如,安装 pytest 用于测试:
pipenv install pytest --dev
  • 这会将 pytest 安装到 [dev - packages] 部分,并在 Pipfile.lock 中记录精确版本。
  • 指定版本安装:可以在安装包时指定版本。例如,要安装 requests 包的 2.25.1 版本:
pipenv install requests==2.25.1
  • Pipfile 中会记录为 requests = "==2.25.1",在 Pipfile.lock 中会记录该版本对应的哈希值等精确信息。
  1. 卸载包
    • 要卸载已经安装的包,可以使用 pipenv uninstall 命令,后面跟上包名。例如,要卸载 numpy 包:
pipenv uninstall numpy
  • 该命令会从虚拟环境中卸载 numpy 包,并从 PipfilePipfile.lock 中移除相关记录。如果 numpy 是其他包的依赖,并且没有其他包依赖它,相关的依赖包也可能会被卸载(具体取决于依赖关系)。
  1. 更新包
    • 更新单个包:要更新某个已安装包到最新版本,可以使用 pipenv update 命令,后面跟上包名。例如,更新 requests 包:
pipenv update requests
  • pipenv 会根据 Pipfile 中的版本约束(如 ~=, ^ 等),将 requests 包更新到合适的最新版本,并更新 PipfilePipfile.lock
  • 更新所有包:要更新项目中的所有包到最新版本,可以直接运行 pipenv update 命令,不带包名:
pipenv update
  • 这会根据 Pipfile 中的版本约束,更新所有包,并重新生成 Pipfile.lock 以记录新的精确版本信息。但要注意,更新所有包可能会引入兼容性问题,尤其是在生产环境中,建议在更新前进行充分的测试。

六、使用虚拟环境

  1. 进入虚拟环境
    • 要进入项目的虚拟环境,可以使用 pipenv shell 命令。在项目目录下运行该命令:
pipenv shell
  • 执行此命令后,命令行提示符会发生变化,显示虚拟环境的相关信息。例如:
(my_project-123abc) my_project $
  • 此时,在这个命令行会话中执行的 pip 命令会操作虚拟环境中的包,而不是系统级的 Python 环境。例如,可以直接运行 pip install 安装包,它会安装到虚拟环境中,并且会更新 PipfilePipfile.lock
  1. 在虚拟环境中运行脚本
    • 可以在不进入虚拟环境的情况下,直接在虚拟环境中运行 Python 脚本。例如,假设项目中有一个 main.py 脚本,可以使用以下命令在虚拟环境中运行它:
pipenv run python main.py
  • pipenv run 会在虚拟环境的上下文中执行指定的命令。这里,它会使用虚拟环境中的 Python 解释器来运行 main.py 脚本,确保脚本使用的是虚拟环境中安装的包。

七、常见问题及解决方法

  1. 包安装失败
    • 网络问题:如果在安装包时遇到网络连接问题,如超时或无法访问 PyPI 服务器,首先检查网络连接是否正常。可以尝试使用 ping 命令检查网络连通性。如果是网络代理问题,可以设置 http_proxyhttps_proxy 环境变量。例如,在 Linux 或 macOS 上:
export http_proxy=http://your_proxy_server:port
export https_proxy=https://your_proxy_server:port

在 Windows 上,可以在系统环境变量中设置这两个变量。

  • 版本冲突:有时,由于包之间的版本依赖冲突,安装可能会失败。pipenv 通常会在安装失败时给出一些提示信息。可以尝试手动指定包的版本,使其满足依赖关系。例如,如果 packageA 需要 packageB 的某个特定版本,而当前安装的 packageB 版本不兼容,可以卸载 packageB 并安装指定版本:
pipenv uninstall packageB
pipenv install packageB==required_version
  1. Pipfile.lock 不一致问题
    • 在多人协作开发项目时,可能会出现 Pipfile.lock 文件不一致的情况。这可能是因为不同开发者在安装包时,由于网络缓存等原因,安装了不同版本的包。解决方法是在更新 Pipfile 后,运行 pipenv lock --clear 命令,然后再运行 pipenv installpipenv lock --clear 会清除 Pipfile.lock 中的现有内容,重新生成一个基于 Pipfile 的全新 Pipfile.lock 文件,确保所有开发者使用一致的依赖版本。
  2. 虚拟环境创建失败
    • Python 版本问题:如果指定的 Python 版本在系统中未安装,虚拟环境创建会失败。需要先安装相应版本的 Python,然后再尝试创建虚拟环境。例如,可以使用 pyenv(在 Linux 和 macOS 上)或 Python 安装程序(在 Windows 上)来安装指定版本的 Python。
    • 权限问题:在某些情况下,由于权限不足,虚拟环境创建可能失败。确保当前用户对项目目录有足够的读写权限。在 Linux 或 macOS 上,可以检查目录的权限设置,必要时使用 chmod 命令修改权限。例如,要赋予当前用户对项目目录的读写执行权限:
chmod -R 755 my_project

通过以上对 pipenv 的详细介绍,你应该能够熟练使用它来管理 Python 项目的虚拟环境和依赖关系,提高项目开发的稳定性和可重复性。在实际项目中,合理运用 pipenv 可以避免许多因包版本冲突和环境不一致导致的问题,让开发过程更加顺畅。