virtualenvvirtualenvwrapper实现了Python第三方库的有效管理 , 但是仍然存在一些可以改进的地方。比如 : requirements.txt 的功能较弱 , 在requirements.txt中仅仅列出了虚拟环境中安装的所有第三方库的名称和版本号 , 没有反应出第三库之间的依赖关系。再比如 : requirements.txt需要手动生成和更新。要手动的执行 pip3 freeze > requirements.txt 才能得到requirements.txt。如果安装或卸载了第三方库 , 需要再次执行指令以得到更新的requirements.txt。再比如 : pipvirtualenv是两个独立的工具 , 能合成一个工具是不是更好呢? 第三方库 Pipenv: Python Development Workflow for Humans 就是综上所述的改进工具 , pip + virtualenv的结合体 , 也是Python官方推荐的第三方库管理工具。

pipenv 是一款比较新的包管理工具 , 其借鉴了 javascriptnpmPHPcomposer 等理念 , 通过一个依赖描述文件 Pipfile 来安装和管理依赖 , 以达到协同开发的目的。如果你熟悉 npm 或者 composer 的话 , 那 pipenv 正合你胃口。pipenv 其实整合了 pipvirtualenv 等库 , 在其上推出了更便捷的使用方式。

1. 安装pipenv

直接使用pip命令安装

pip3 install pipenv

设置命令行的自动补全功能

如果使用的bash shell , 请将以下代码添加到.bashrc.bash_profile文件内:

eval "$(pipenv --completion)"

命令详解 :

$ pipenv
Usage: pipenv [OPTIONS] COMMAND [ARGS]...
 
Options:
  --where             输出项目根目录相关信息
  --venv              输出virtualenv相关信息
  --py                输出Python解释器相关信息
  --envs              输出环境变量选项
  --rm                删除virtualenv
  --bare              最小化输出
  --completion        命令自动补全
  --man               显示man页面
  --three / --two     在创建virtualenv时使用Python3或Python2
  --python TEXT       指定创建virtualenv时使用的具体的Python版本
  --site-packages     为virtualenv启用site-packages [env变量 : PIPENV_SITE_PACKAGES]
  --clear             清除缓存(pipenv , pip和pip-tools ) [env变量 : PIPENV_CLEAR]
  --pypi-mirror TEXT  指定一个PyPI镜像
  --version           显示版本信息并退出
  -h, --help          显示帮助信息并退出
 
 
使用示例:
   创建一个项目 , 并明确指定使用Python3.7:
   $ pipenv --python 3.7
 
   删除项目的virtualenv (inferred from current directory):
   $ pipenv --rm
 
   为项目安装所有依赖项 (including dev):
   $ pipenv install --dev
 
   创建包含pre-releases的lockfile文件:
   $ pipenv lock --pre
 
   将已安装的依赖项显示为图表:
   $ pipenv graph
 
   检查已安装的依赖项是否存在安全漏洞:
   $ pipenv check
 
   安装一个本地的setup.py到你的虚拟环境或Pipfile:
   $ pipenv install -e .
 
   使用原生的pip命令:
   $ pipenv run pip freeze
 
Commands:
  check      根据 Pipfile 中提供的PEP 508标记检查安全漏洞
  clean      卸载所有 Pipfile.lock 未指定的包
  graph      显示当前安装的依赖项的关系图信息
  install    如果未指定要安装的包 , 则会安装 Pipfile 中的所有包 , 否则 , 只安装指定的包
  lock       生成 Pipfile.lock 文件
  open       在编辑器中查看给定的模块
  run        运行virtualenv中已安装的命令
  shell      在virtualenv内启动一个shell
  sync       安装 Pipfile.lock 中指定的所有的包
  uninstall  卸载一个指定的包并将其从 Pipfile 中移除
  update     先运行lock命令 , 在运行sync命令

2. pipenv虚拟环境管理

2.1 虚拟环境创建与激活

  • 创建虚拟环境

    [root@host-192-168-71-25 ~]# mkdir /data/projenv8
    [root@host-192-168-71-25 ~]# cd /data/projenv8
    [root@host-192-168-71-25 projenv8]# ls
    [root@host-192-168-71-25 projenv8]# pipenv install 
    Creating a virtualenv for this project
    Pipfile: /data/projenv8/Pipfile
    Using /usr/bin/python3.12.9 to create virtualenv...
    ⠴ Creating virtual environment...created virtual environment CPython3.12.9.final.0-64 in 258ms
      creator CPython3Posix(dest=/root/.virtualenvs/projenv8-73W4Qy2h, clear=False, no_vcs_ignore=False, global=False)
      seeder FromAppData(download=False, pip=bundle, via=copy, app_data_dir=/root/.local/share/virtualenv)
        added seed packages: pip==25.1.1
      activators BashActivator,CShellActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator
    ​
    ✔ Successfully created virtual environment!
    Virtualenv location: /root/.virtualenvs/projenv8-73W4Qy2h
    Creating a Pipfile for this project...
    Pipfile.lock not found, creating...
    Locking  dependencies...
    Locking  dependencies...
    Updated Pipfile.lock (702ad05de9bc9de99a4807c8dde1686f31e0041d7b5f6f6b74861195a52110f5)!
    To activate this project's virtualenv, run pipenv shell.
    Alternatively, run a command inside the virtualenv with pipenv run.
    Installing dependencies from Pipfile.lock (2110f5)...

    上面的命令会自动在~/.virtualenvs/目录下创建虚拟环境目录 , 名字为一个当前目录名加一串随机字符串的虚拟环境目录。这里是projenv8-73W4Qy2h

    下面多了两个文件 , 为PipfilePipfile.lock , 用于存放依赖包名的文件。类似php里的composer.jsoncomposer.lock

    [root@host-192-168-71-25 projenv8]# ls 
    Pipfile  Pipfile.lock
  • 查看虚拟环境

    [root@host-192-168-71-25 projenv8]# pipenv --venv
    /root/.virtualenvs/projenv8-73W4Qy2h

    我们的虚拟环境目录在/root/.virtualenvs/下面 , 是因为我们之前设置过环境变量

    export WORKON_HOME=$HOME/.virtualenvs
  • 激活虚拟环境 , 直接切换到对应目录/data/projenv8并运行命令pipenv shell即可

    [root@host-192-168-71-25 projenv8]# cd /data/projenv8/
    [root@host-192-168-71-25 projenv8]# pipenv shell
    Launching subshell in virtual environment...
     source /root/.virtualenvs/projenv8-73W4Qy2h/bin/activate
    [root@host-192-168-71-25 projenv8]#  source /root/.virtualenvs/projenv8-73W4Qy2h/bin/activate
    (projenv8) [root@host-192-168-71-25 projenv8]# 

    激活过程中如果出现下面类似告警:

    Warning: Your Pipfile requires python_version 2.7, but you are using 3.9.9 (/root/./m/bin/python).

    原因 : 这是因为创建虚拟环境的时候 , 没有指定python解释器 , Pipfile就使用系统默认的python解释器了 , 就是2.7.5 , 但是pipenv却是使用系统最新的解释器3.9

    解决办法:

    • 办法一 : 手动修改Pipfile

      手动修改Pipfile文件里的python_version

      注意 : Pipfile.lock里的也要修改

      vim Pipfile
       
      [[source]]
      url = "https://pypi.org/simple"
      verify_ssl = true
      name = "pypi"
       
      [packages]
       
      [dev-packages]
       
      [requires]
      python_version = "3.9"
    • 办法二 : 删除虚拟环境 , 重新创建虚拟环境

      删除虚拟环境后 , 再次安装会覆盖之前的Pipfile , 使用新环境。如果不删除 , 无法覆盖。

      # pipenv --rm删除当前虚拟环境 , 注意Pipfile不会被删掉
      [root@ops-130 myproj10]# pipenv --rm
      # 使用pipenv重新安装 , 指定解释器版本为3.X
      [root@ops-130 myproj10]# pipenv install --three
      # 此时再次查看Pipfile版本就和环境一致了。
      [root@ops-130 myproj10]# cat Pipfile
  • 退出虚拟环境 : exit

    (projenv8) [root@host-192-168-71-25 projenv8]# exit
    exit
    [root@host-192-168-71-25 projenv8]# 
  • 删除虚拟环境

    [root@host-192-168-71-25 projenv8]# pipenv --rm
    Removing virtualenv (/root/.virtualenvs/projenv8-73W4Qy2h)...

2.2 创建虚拟环境的多种方式

pipenv创建虚拟环境有多种方式 , 这里总结一下 :

  • 方式一: 指定解释器创建虚拟环境

    # 创建虚拟环境 , 指定使用python3
    pipenv --three
    ​
    # 或者
    pipenv --python 3.9

    这种方式是指定python解释器 , 并创建虚拟环境。

    它会在当前目录生成Pipfile , 不会生成Pipfile.lock

  • 方式二: 安装所有依赖时创建虚拟环境

    # 创建虚拟环境
    pipenv install

    这种方式是在安装依赖包的同时创建虚拟环境。

    因为pipenv install , 就是根据Pipfile来安装所有依赖 , 类似npm install

    如果当前目录没有Pipfile , 它就会自动创建Pipfile并创建虚拟环境。

    因为这种方式它已经在安装所有依赖了 , 所以不仅会创建Pipfile , 也会创建Pipfile.lock文件。

    同时 , 它创建虚拟环境后 , 也会自动进入环境 , 但是也不会显示前缀。

  • 方式三 : 激活时创建虚拟环境

    # 激活 , 如果环境不存在 , 则创建虚拟环境并激活
    pipenv shell

    这个命令主要用于激活环境 , 但是如果环境不存在 , 则会先创建虚拟环境 , 并同时激活虚拟环境。

    这种方式因为使用了pipenv shell激活了 , 所以创建虚拟环境后 , 也会自动进入虚拟环境 , 并激活。

    会显示虚拟环境前缀。

2.3 创建虚拟环境目录位置

  • 方式一:

    # 设置这个环境变量 , pipenv会在当前目录下创建.venv的目录 , 以后都会把模块装到这个.venv下。
    export PIPENV_VENV_IN_PROJECT=1
  • 方式二:

    # 自己在项目目录下手动创建.venv的目录 , 然后运行 pipenv run 或者 pipenv shell pipenv都会在.venv下创建虚拟环境。
    mkdir .venv
    pipenv shell
  • 方式三 :

    # 设置WORKON_HOME到其他的地方 ( 如果当前目录下已经有.venv,此项设置失效 ) 。
    export WORKON_HOME=$HOME/.virtualenvs

小技巧: 如果子级目录的父级目录已经创建过虚拟环境, 则子级目录无法创建虚拟目录(子级目录无法生成Pipfile, 子级默认会使用父级的虚拟环境), 如果确实需要在子级目录创建独立的虚拟环境,可以运行pipenv --where 获取父级虚拟环境的名字, 根据虚拟环境的前半部分名字, 确定父级目录的位置, 然后删除父级目录下的Pipfile, Pipfile.lock, 运行exit退出父级虚拟环境,然后回到子目录,运行pipenv --three创建子目录的虚拟环境即可

2.4 相关定位操作

  • 定位项目目录

    [root@host-192-168-71-25 projenv8]# pipenv --where
    /data/projenv8
  • 定位虚拟环境目录, 即virtualenv目录

    [root@host-192-168-71-25 projenv8]# pipenv --venv
    /root/.virtualenvs/projenv8-73W4Qy2h
  • 定位Python解释器:

    [root@host-192-168-71-25 projenv8]# pipenv --py
    /root/.virtualenvs/projenv8-73W4Qy2h/bin/python

3. pipenv包管理

  • 安装依赖包 :

    安装相关依赖包, 并加入到Pipfile

    pipenv install flask

    它会在当前环境安装flask依赖包 , 并记录flask包名以及版本信息 , 记录到Pipfile里。

    如果安装的时候 , 没有指定包名 , 默认是最新的 , 会记录为“*

    注意 : Pipfile只会记录你install里指定的包 , 但是这个flask包本身所依赖的包不会记录 ,

    但是所有的依赖详情都会记录到Pipfile.lock中。

    image-20250812000221370

    查看目前安装的库及其依赖关系

    pipenv graph

    这里所有的完整依赖关系, 这些会记录到Pipfile.lock

    (projenv8) [root@host-192-168-71-25 projenv8]# pipenv graph
    Flask==3.1.1
    ├── blinker 
    ├── click 
    ├── itsdangerous 
    ├── Jinja2 
    │   └── MarkupSafe 
    ├── MarkupSafe 
    └── Werkzeug 
        └── MarkupSafe 
    ​

    Pipfile会记录当前虚拟环境安装的所有依赖包及其对应的版本 , 当我们需要迁移项目 , 部署新项目 , 或者有新人接手时 , 就可以直接拿到这个PipfilePipfile.lock文件 , 直接pipenv install即可 , 它就会按照Pipfile里的包 , 把所有的依赖文件都安装上 , 是不是很方便。

    安装所有依赖包:

    # 根据Pipfile的记录 , 安装所有依赖包
    pipenv install

  • 指定安装包版本

    你可以使用 语义化(https://semver.org/)的版本控制方案 指定包的版本。例如 major.minor.micro

    例如 , 你可以使用如下的命令安装 requests :

    pipenv install requests~=1.2   # 相当于 requests~=1.2.0

    Pipenv 将安装 1.2 版本和任何 minor 版本的更新 , 但不会安装 2.0 版本。

    上面的命令将会自动更新 Pipfile 文件以体现这个特殊的需求。

    通常 , Pipenv使用与pip相同的参数格式。但是 , 请注意 , 根据PEP 440 , 您不能使用包含连字符或加号的版本号。

    要指定包含或者排除具体的版本 , 您可以使用如下命令 :

    pipenv install "requests>=1.4"   # 只安装等于或者大于 1.4.0 的版本
    pipenv install "requests<=2.13"  # 只安装小于或者等于 2.13.0 的版本
    pipenv install "requests>2.19"   # 安装 2.19.1 版本但是不安装 2.19.0 版本

    注意 : 强烈建议使用双引号包裹包名和版本号以避免unix操作系统中的输入和输出重定向问题。

    请优先使用 ~= 标识符而不是 == 标识符 , 因为后者会阻止 pipenv 更新包 :

    pipenv install "requests~=2.2"  # 锁定包的主版本(这相当于使用==2.*)

    要避免安装某个特定的版本 , 可以使用 != 标识符。

    要深入解释有效标识符和更复杂的用例 , 请查看 PEP-440 的相关部分。

    https://www.python.org/dev/peps/pep-0440/#version-specifiers%3E

  • 卸载依赖包

    卸载指定包:

    pipenv uninstall flask

    卸载包后 , 相关包和依赖详情会从PipfilePipfile.lock中移除。

    image-20250812002021200

    卸载当前环境所有包:

    # 从虚拟环境中移除所有已安装的包 , 但 Pipfile.lock 文件不受影响
    pipenv uninstall --all

    卸载开发包:

    # 从虚拟环境中卸载所有开发包 , 并从 Pipfile 文件中移除这些包
    pipenv uninstall –all-dev
  • 更新依赖包 :

    查看所有需要更新的包:

    pipenv update --outdated

    如下图:

    1307747-20220112085726341-1635277146

    更新指定包:

    pipenv update <包名>

    更新所有包:

    pipenv update

    检查安全漏洞:

    pipenv check  # 检查安全漏洞

    它可能会检查出很多错误 , 其实如果不影响你使用 , 你可以直接忽略掉。强迫症患者也可以一个一个问题去解决。

    比如如下问题:

    1307747-20220112085727072-2019530356

  • 修改pipenv的镜像源

    可以修改当前目录下Pipfile文件 , 将[source]下的url属性改成国内的源即可:

    [[source]]
    url = "https://mirrors.aliyun.com/pypi/simple"
    verify_ssl = true
    name = "pypi"

4. 环境部署

使用pipenv进行多环境部署

dev与正式环境区分安装。

当你想要一个包只在开发环境使用 , 等生产部署的时候 , 不需要该安装包 , 你可以这样指定环境安装。

# 把django安装在开发环境
pipenv install django --dev

安装如下图

1307747-20220112085727735-1645057748

安装完成后 , 查看Pipfile文件 :

会发现 , pipenv已经将安装包区分开来了。

[dev-packages] 里记录的--dev开发环境安装的包

[package] 里记录的是没有加环境参数 , 默认就是正式环境的包。

1307747-20220112085728295-1439706244

那么等到你真正迁移到生产环境部署的时候 , 就只需要这么做 :

pipenv install 

这样默认是只安装[package] 里的安装包的 , 会自动过滤掉[dev-packages] 里的包。

让生产环境变得更加纯净 , 避免有多余的包。

如下 : 这是直接pipenv install的 , 里面是没有django包的

1307747-20220112085728977-2130912704

如果你要迁移到开发环境 , 只需要这么做 :

pipenv install --dev

它就会把[dev-packages] 里的包也一起安装上了。

如下 :

这是使用了--dev参数的 , 看到已经把djiango安装上了。

1307747-20220112085729743-323015776

5. Pipfile.lock文件

Pipfile.lock 利用了pip中一些新的安全改进。默认情况下 , Pipfile.lock 包含每个下载的包的 sha256 哈希值。这可以使pip能够保证从不信任的PyPI源安装包时或者在不稳定的网络环境下安装包时都能保证包的正确性与完整性。我们强烈建议通过将项目从开发环境提升到生产环境来进行部署。您可以使用 pipenv lock 编译开发环境上的依赖项 , 并将编译后的 Pipfile.lock 文件部署到您所有的生产环境 , 以便进行可重现的构建。

(使用Pipfile.lock可以锁定之前的安装包 , 确保迁移重新部署后 , 能够重现跟之前一样的环境。)

PipfilePipfile.lock不一致

因为使用pipenv install的时候 , 加上--ignore-lock参数 , 可以忽略 Pipfile.lock 文件而直接安装 Pipfile 中的包。此外 , 不会更新 Pipfile.lock 文件。

pipenv install安装一些比较大的包 , 比如TensorFlow等科学包 , 在安装完包 , 正在解析包依赖的时候 , 可能会花费很长时间 , 可能就会ctrl+C停止掉了 , 此时包已经安装完成 , Pipfile已经写入完成 , 但是没有解析完依赖 , 所以Pipfile.lock没有写入完成。

这两种情况都会导致PipfilePipfile.lock不一致的情况 , 会对应不上。

此时 , 可以使用Pipenv lock重新生成Pipfile.lock文件。

pipenv lock

如果通过 pipenv 命令安装和卸载 package , 安装或卸载完成后还会更新 Pipfile.lock 文件 , 有时候会卡在这个步骤。通常可以 ctrl+c 强制推出 , 删除 Pipfile.lock, 然后 使用命令重新生成Pipfile.lock文件

# 重新生成Pipfile.lock文件
pipenv lock

默认情况下 , 使用pipenv install , 它会重新解析Pipfile里安装包的依赖性 , 并将依赖关系更新到Pipfile.lock中。如果你不想要重新解析Pipfile里安装包 , 只想安装Pipfile.lock文件中现存的依赖包 , 可以精确的指定只使用Pipfile.lock文件。

pipenv sync

可以使用 sync 命令精确安装 Pipfile.lock 文件中指定的包 :

pipenv sync

注意 : pipenv install --ignore-pipfilepipenv sync 命令很相似 , 但是pipenv sync 命令永远不会尝试重新锁定依赖项 , 因为它被认为是一个原子操作。默认情况下 , 除非使用了 --deploy 标志 , 否则 pipenv install 会尝试重新锁定依赖项。

pipenv install --deploy

可以使用 --deploy 标志强制Pipfile.lock 文件是最新的。

上述命令将在Pipfile.lock 文件不是最新的时候导致构建失败 , 而不是生成一个新的。

6. 兼容requirements.txt

之前我们的pip工具可以从requierments.txt文件中导入依赖包。

  • pipenv , 用下面的命令就可以将PipfilePipfile.lock文件里面的包导出为requirements.txt文件。

    # 将Pipfile里的全部包导出到requirements.txt
    pipenv lock -r > requirements.txt

    1307747-20220112085730377-1993652073

  • 选择只导出开发环境的包:

    # 只导出开发环境的包
    pipenv lock -r --dev-only > requirements.txt

    1307747-20220112085730944-1264914508

  • 导出开发环境+ 默认环境的包:

    # dev环境和default环境的包都会导出
    pipenv lock -r --dev > requirements.txt

    1307747-20220112085731539-768166954

  • 使用底层pip的命令导出:

    pipenv run pip freeze > requirements.txt

    1307747-20220112085732066-680637879

  • 导入requirements.txt

    导出为requirements.txt后 , 可以通过pip导入 , 也可以通过pipenv导入。

    # 通过pip导入
    pip install -r requirements.txt
    # 通过pipenv导入
    pipenv install -r requirements.txt

7. 虚拟环境中运行命令

  • 启动shell运行

    正常来说 , 如果想要让命令运行在虚拟环境 , 需要启动一个虚拟环境的shell , 否则命令还是在系统环境下运行的 , 如下 :

    pipenv shell 

    1307747-20220112085732680-380797655

  • 使用run运行

    如果不想启动shell , 而是直接在虚拟环境中执行命令 , 可以使用run:

    # pipenv run <命令>
    pipenv run python --version

    1307747-20220112085733215-448644748

    部署项目的时候 , 你也可以不进入虚拟环境的方式运行项目 :

    pipenv run python xxx.py

8. 环境变量: (.env)

  • 自动加载.env文件(利器)

    .env文件可以设置一些环境变量 , 在程序开发的时候模拟环境变量。

    如果项目目录下包含一个 .env 文件 , 它会被 pipenv shellpipenv run 命令自动加载 :

    # 如下 , 设置一个变量HELLO , 以及配置文件路径的变量
    [root@ops-130 myproj10]# cat .env 
    HELLO=WORLD
    CONFIG_PATH=${HOME}/.config/foo
     
     
    # 测试环境变量
    # 使用pipenv run的时候 , 会自动加载该环境变量。
    [root@ops-130 myproj10]# pipenv run python
    Loading .env environment variables...
    Python 3.9.9 (main, Dec 31 2021, 15:34:46) 
    [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import os
    >>> os.environ['HELLO']
    'WORLD'
    >>> os.environ['CONFIG_PATH']
    '/root/.config/foo'
    >>>

    这类似于phplavel框架的.env文件。

    这对于将生产凭证排除在代码库之外非常有用。我们不建议将 .env 文件提交到源代码控制中!

    如果你的 .env 文件位于不同的路径下或者有其他名称 , 你可以设置一个PIPENV_DOTENV_LOCATION 环境变量:

    PIPENV_DOTENV_LOCATION=/path/to/.env pipenv shell

    要禁止pipenv加载 .env 文件 , 可以设置 PIPENV_DONT_LOAD_ENV 环境变量:

    PIPENV_DONT_LOAD_ENV=1 pipenv shell
  • Pipfile引用环境变量

    Pipfile中也可以引用环境变量的值 , 格式为${MY_ENVAR}$MY_ENVAR , 在Windows系统中还支持%MY_ENVAR%

    [[source]]
    url = "https://${PYPI_USERNAME}:${PYPI_PASSWORD}@my_private_repo.example.com/simple"
    verify_ssl = true
    name = "pypi"
     
    [packages]
    flask = "*"
    jieba = "*"
     
    [dev-packages]
    django = "*"
     
    [requires]
    python_version = "3.9"

    这里的变量为:${PYPI_USERNAME}:${PYPI_PASSWORD}

    使用前提是 , 系统中要已经设置了相关的变量。

    当然你可以结合.env文件 , 将相关变量设置在.env里。

  • setup.py安装依赖包

    很多依赖库都包含setup.py文件 , 里面也包含了对应包的子依赖信息 , 这个文件跟Pipfile.lock有点相似 , pipenv也提供了堆setup.py的支持。

    pipenv也可以从setup.py安装:

    pipenv install -e .

9. 优缺点分析

  1. pipenv集成了pip , virtualenv两者的功能 , 且完善了两者的一些缺陷。

  2. 支持Python2Python3 , 在各个平台的命令都是一样的。

  3. 类似npm , 容易迁移 , 便于项目内部协同工作

  4. 各个地方使用了哈希校验 , 无论安装还是卸载包都十分安全 , 且会自动公开安全漏洞。

  5. 通过加载.env文件简化开发工作流程。

  6. Bug 很多 , 确实比较年轻 , 安装的流程有些让人困惑 , 不像 pip 这么直接好理解


参考链接

pipenv使用 | CHEGVA

Python多环境管理神器(pipenv ) - doublexi - 博客园


熊熊