关于Python虚拟环境与包管理你应该知道的事

栏目: 编程工具 · 发布时间: 6年前

内容简介:关于我编程界的一名小程序猿,目前在一个创业团队任team lead,技术栈涉及Android、Python、Java和Go,这个也是我们团队的主要技术栈。 联系:hylinux1024@gmail.com

关于我

编程界的一名小程序猿,目前在一个创业团队任team lead,技术栈涉及Android、 PythonJava 和Go,这个也是我们团队的主要技术栈。 联系:hylinux1024@gmail.com

Python 拥有大量的第三方库,引用这些库也非常方便,通过 pip install 就可以将这些第三方库安装到本地 Python 库文件目录中,然后就可以 import 到项目中,极大地提升了开发者的编码效率。

但这也带来了一个问题:当 A 项目和 B 项目同时引用 Lib 库,而 A 项目需要 Lib 版本是1.0, B 项目需要 Lib 的版本是2.0。 这样在使用 pip install 命令将 Lib 直接安装到本地全局环境中就会发生冲突,有可能会导致 AB 的运行环境无法同时得到满足而运行失败。

于是虚拟环境( virtualenv )就出现了。它的核心思想就是 为每个项目提供独立的运行环境 ,这样不同的项目依赖库就不会冲突。

0x00 使用venv+pip

1、创建venv

安装虚拟环境也非常简单,可以使用 venv 模块,例如在项目目录中使用 Python3 创建一个虚拟环境

➜ python3 -m venv venv
复制代码

于是在项目目录中就多了一个 venv 的文件目录。这个目录就是该项目的虚拟环境。

要使用虚拟环境就必须激活

➜ source venv/bin/activate
复制代码

然后在命令行中就会出现

(venv) ➜  
复制代码

说明虚拟环境已经激活。

要取消虚拟环境,使用

(venv) ➜ deactivate
复制代码

2、使用pip install/uninstall

激活虚拟环境后就可以使用 pip 命令安装项目的依赖库。例如

(venv) ➜ pip install requests
复制代码

pip 会将 requests 安装到 venv/lib/python3.7/site-packages 目录中。

要卸载依赖库

(venv) ➜ pip uninstall requests
复制代码

3、pip list

要查看 venv 中安装了哪些依赖库

(venv) ➜ pip list
Package        Version 
-------------- --------
beautifulsoup4 4.7.1   
certifi        2019.3.9
requests        2.21.0    
复制代码

4、pip freeze

使用 pip freeze 可以将依赖库列表保存到一个 requirements.txt 文件,可以让其他项目的协作者可以快速地建立项目的运行环境。

(venv) ➜ pip freeze > requirements.txt
复制代码

于是要安装项目依赖

(venv) ➜ pip install -r requirements.txt
复制代码

这样就可以建立一个统一的运行环境了。

5、venv+pip方案存在的问题

到目前为止一切都运行良好,这应该是不错的解决方案了吧。实际上这种方案我一直都在使用,目前也是,也并没有遇到什么问题。

直到有一天 有人说使用 venv+pip 也不能保证我的运行环境的一致性和可靠性 。 他的理由也很简单,项目的库环境是依赖 requirements.txt ,而 requirements.txt 中库有没有指定版本号,这样在使用 pip install -r requirements.txt 的时候也会导致安装不确定的版本。

例如

beautifulsoup4  
certifi        
requests        
复制代码

当然可以为每个库指定确切的版号来解决,于是

beautifulsoup4 4.7.1   
certifi        2019.3.9
requests        2.21.0 
复制代码

这样做可以解决上面的问题,但是如果某个第三方库修补了一个漏洞,要使用 pip install --upgrade 更新这些依赖库的话,就不是那么容易了。

还有一个问题 requirements.txt 中的依赖库也有可能会出现版本号冲突。 情况是这样:

ALib -> sublib_1.0
BLib -> sublib_2.1
复制代码

ALibBLib 同时依赖于 sublib ,但它们依赖的版本不一样,最终在使用 pip install -r requirements.txt 也可能会 因为依赖库中的子依赖库版本不兼容而导致项目运行失败。

于是就出现了 pipenv

0x01 pipenv

说实话在这之前我一直都是使用 venv+pip ,当看到上面的问题之后,我觉得有必要了解一下 pipenv

1、 安装 pipenv

➜ pip install pipenv
复制代码

一旦安装完成就会引用两个文件, PipfilePipfile.lock 。前者是用于取代 requirements.txt 文件的,后者则是用于保证依赖库的确定性和一致性。

实际上, pipenv 命令底层也是封装了 pipvenv 的操作,并提供了一套简单的交互命令。

创建虚拟环境

要在项目目录下(如 pipenvdemo )使用

➜ pipenv shell
复制代码

当出现类似以下信息时说明虚拟环境创建并激活成功,当然还可以使用 --two--three 参数指定使用 Python2 还是 Python3 来创建,也可以使用确定的 Python 版本号如 --python3.7

➜ pipenv shell --three

➜ pipenv shell --python3.7
复制代码

由于我电脑本地 Python 环境是3.7,所以这里直接默认它会指向本地默认版本

Creating a virtualenv for this project…
Pipfile: /Users/mac/PycharmProjects/pipenvdemo/Pipfile
Using /usr/local/opt/python/bin/python3.7 (3.7.3) to create virtualenv…
⠋ Creating virtual environment...Already using interpreter /usr/local/opt/python/bin/python3.7
Using base prefix '/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7'
New python executable in /Users/mac/.local/share/virtualenvs/pipenvdemo-fHPp2Wq9/bin/python3.7
Also creating executable in /Users/mac/.local/share/virtualenvs/pipenvdemo-fHPp2Wq9/bin/python
Installing setuptools, pip, wheel...
done.

✔ Successfully created virtual environment!
Virtualenv location: /Users/mac/.local/share/virtualenvs/pipenvdemo-fHPp2Wq9
Creating a Pipfile for this project…
Launching subshell in virtual environment…
 . /Users/mac/.local/share/virtualenvs/pipenvdemo-fHPp2Wq9/bin/activate
复制代码

同时在项目目录下(如 pipenvdemo )生成一个 Pipfile 文件。类似的,命令行也会出现以下样式

(pipenvdemo) ➜ pipenvdemo
复制代码

其中 Pipfile 的内容为

[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]

[packages]

[requires]
python_version = "3.7"
复制代码

2、pipenv install

当要安装第三方库当时候就直接使用 pipenv install 命令,以下指定 flask 版本号进行安装。

➜ pipenv install flask==1.0.1
复制代码

也可以不指定版本号

➜ pipenv install flask
复制代码

终端会出现类似以下信息

Installing flask==1.0.1…
Adding flask to Pipfile's [packages]…
✔ Installation Succeeded
Pipfile.lock not found, creating…
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
⠙ Locking...
复制代码

还可以使用 --dev 参数用于安装开发环境依赖的库

➜ pipenv install pytest --dev
复制代码

在项目目录又生成了另一文件 Pipfile.lock ,并且 Pipfile 文件也会更新

[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]
pytest = "*"

[packages]
flask = "==1.0.1"

[requires]
python_version = "3.7"
复制代码

看到在 [packages] 标签下列出了依赖库 flask 和版本号,上面还有一个 [dev-packages] 是用于标示开发版本依赖库,这样可以用于区分生产环境和开发环境。只有在命令中使用了 --dev 参数才会安装 [dev-packages] 下列出的依赖库。

Pipfile.lock 文件的内容要丰富一些,主要是 包含了依赖库(包括子依赖库)的版本号以及文件 hash 的信息,从而可以保证依赖库是确定的。

{
    "_meta": {
        "hash": {
            "sha256": "3bba1f1c4de8dd6f8d132dda17cd3c720372a1eed94b9523b9c23013e951c8ae"
        },
        "pipfile-spec": 6,
        "requires": {
            "python_version": "3.7"
        },
        "sources": [
            {
                "name": "pypi",
                "url": "https://pypi.org/simple",
                "verify_ssl": true
            }
        ]
    },
    "default": {
        "click": {
            "hashes": [
                "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
                "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"
            ],
            "version": "==7.0"
        },
        "flask": {
            "hashes": [
                "sha256:cfc15b45622f9cfee6b5803723070fd0f489b3bd662179195e702cb95fd924c8",
                "sha256:dbe2a9f539f4d0fe26fa44c08d6e556e2a4a4dd3a3fb0550f39954cf57571363"
            ],
            "index": "pypi",
            "version": "==1.0.1"
        },
        "itsdangerous": {
            "hashes": [
                "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
                "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"
            ],
            "version": "==1.1.0"
        },
        "jinja2": {
            "hashes": [
                "sha256:065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013",
                "sha256:14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b"
            ],
            "version": "==2.10.1"
        },
        "markupsafe": {
            "hashes": [
                "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
                "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
                "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
                "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
                "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
                "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
                "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
                "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
                "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
                "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
                "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
                "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
                "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
                "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
                "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
                "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
                "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
                "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
                "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
                "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
                "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
                "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
                "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
                "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
                "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
                "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
                "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
                "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"
            ],
            "version": "==1.1.1"
        },
        "werkzeug": {
            "hashes": [
                "sha256:865856ebb55c4dcd0630cdd8f3331a1847a819dda7e8c750d3db6f2aa6c0209c",
                "sha256:a0b915f0815982fb2a09161cb8f31708052d0951c3ba433ccc5e1aa276507ca6"
            ],
            "version": "==0.15.4"
        }
    },
    "develop": {}
}
复制代码

3、pipenv lock

假设我们要把项目发布到生产环境了,这时就要使用 pipenv lock 命令

➜ pipenv lock
复制代码

终端会出现类似如下信息

Locking [dev-packages] dependencies…
✔ Success!
Locking [packages] dependencies…
复制代码

这个命令会创建或更新 Pipfile.lock 文件,需要注意的是我们不应该手动修改此文件。

然后就可以在生产环境中使用以下命令恢复环境

➜ pipenv install --ignore-pipfile
复制代码

指定 --ignore-pipfile 参数的意思是,只要恢复 Pipfile.lock 的列表的依赖库和子依赖库。如果要恢复开发环境中的依赖库,即安装 [dev-packages] 下面的依赖库,可以使用

➜ pipenv install --dev
复制代码

以上就是 pipenv 的简单用法。

4、pipenv graph

现在再来看看前面提到的问题

ALib -> sublib_1.0
BLib -> sublib_2.1
复制代码

AB 模块都依赖同一个库,但依赖库的版本号不一样。这时使用 pipenv install 就出现类似以下信息

Warning: Your dependencies could not be resolved. You likely have a mismatch in your sub-dependencies.
  You can use $ pipenv install --skip-lock to bypass this mechanism, then run $ pipenv graph to inspect the situation.
Could not find a version that matches sublib=1.0,sublib=2.1
复制代码

可以使用

➜ pipenv graph
复制代码

查看当前项目依赖库及其子依赖库信息,以树层级方式进行展示

Flask==1.0.1
  - click [required: >=5.1, installed: 7.0]
  - itsdangerous [required: >=0.24, installed: 1.1.0]
  - Jinja2 [required: >=2.10, installed: 2.10.1]
    - MarkupSafe [required: >=0.23, installed: 1.1.1]
  - Werkzeug [required: >=0.14, installed: 0.15.4]
pytest==4.6.2
  - atomicwrites [required: >=1.0, installed: 1.3.0]
  - attrs [required: >=17.4.0, installed: 19.1.0]
  - importlib-metadata [required: >=0.12, installed: 0.17]
    - zipp [required: >=0.5, installed: 0.5.1]
  - more-itertools [required: >=4.0.0, installed: 7.0.0]
  - packaging [required: Any, installed: 19.0]
    - pyparsing [required: >=2.0.2, installed: 2.4.0]
    - six [required: Any, installed: 1.12.0]
  - pluggy [required: >=0.12,<1.0, installed: 0.12.0]
    - importlib-metadata [required: >=0.12, installed: 0.17]
      - zipp [required: >=0.5, installed: 0.5.1]
  - py [required: >=1.5.0, installed: 1.8.0]
  - six [required: >=1.10.0, installed: 1.12.0]
  - wcwidth [required: Any, installed: 0.1.7]
复制代码

本例中我们安装了 flaskpytestpipenv graph 命令展示了它们各自需要的依赖。还可以加上 --reverse 参数

➜ pipenv graph --reverse
复制代码

使用这个参数可以很方便的分析出冲突的库。

atomicwrites==1.3.0
  - pytest==4.6.2 [requires: atomicwrites>=1.0]
attrs==19.1.0
  - pytest==4.6.2 [requires: attrs>=17.4.0]
click==7.0
  - Flask==1.0.1 [requires: click>=5.1]
itsdangerous==1.1.0
  - Flask==1.0.1 [requires: itsdangerous>=0.24]
MarkupSafe==1.1.1
  - Jinja2==2.10.1 [requires: MarkupSafe>=0.23]
    - Flask==1.0.1 [requires: Jinja2>=2.10]
more-itertools==7.0.0
  - pytest==4.6.2 [requires: more-itertools>=4.0.0]
pip==19.1.1
py==1.8.0
  - pytest==4.6.2 [requires: py>=1.5.0]
pyparsing==2.4.0
  - packaging==19.0 [requires: pyparsing>=2.0.2]
    - pytest==4.6.2 [requires: packaging]
setuptools==41.0.1
six==1.12.0
  - packaging==19.0 [requires: six]
    - pytest==4.6.2 [requires: packaging]
  - pytest==4.6.2 [requires: six>=1.10.0]
wcwidth==0.1.7
  - pytest==4.6.2 [requires: wcwidth]
Werkzeug==0.15.4
  - Flask==1.0.1 [requires: Werkzeug>=0.14]
wheel==0.33.4
zipp==0.5.1
  - importlib-metadata==0.17 [requires: zipp>=0.5]
    - pluggy==0.12.0 [requires: importlib-metadata>=0.12]
      - pytest==4.6.2 [requires: pluggy>=0.12,<1.0]
    - pytest==4.6.2 [requires: importlib-metadata>=0.12]
复制代码

5、其它命令

删除一个依赖包

➜ pipenv uninstall numpy
复制代码

删除所有依赖库

➜ pipenv uninstall --all

➜ pipenv uninstall --all-dev
复制代码

--all-dev 是指定删除所有 开发环境 的依赖。

查看 venv 目录路径

➜ pipenv --venv

/Users/mac/.local/share/virtualenvs/pipenvdemo-fHPp2Wq9
复制代码

查看当前项目路径

➜ pipenv --where

/Users/mac/PycharmProjects/pipenvdemo
复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Operating Systems

Operating Systems

Remzi Arpaci-Dusseau、Andrea Arpaci-Dusseau / Arpaci-Dusseau Books / 2012-8-19 / USD 21.00

A book about modern operating systems. Topics are broken down into three major conceptual pieces: Virtualization, Concurrency, and Persistence. Includes all major components of modern systems includin......一起来看看 《Operating Systems》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

随机密码生成器
随机密码生成器

多种字符组合密码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具